- 栈管运行,堆管存储
一一对应
1. 一个java进程对应一个jvm实例
2. 一个jvm实例对应一个Runtime类
3. 一个Runtime类对应一个堆空间
1. 基本概念
1. Java堆区在Jvm启动后就会被创建,其空间大小就确定了
2. JVM管理的最大的一块内存空间, 空间大小可以调节
3. 堆可以出于物理上不连续的内存空间,但在逻辑上它应该视为连续的
4. 所有的线程共享java堆
细分:(线程私有的缓冲区(Thread Local Allocaation Buffer(TLAB), 堆主存储))
2. 核心概念
1. 所有的 对象实例 和 数组 都在堆上分配内存
2. 数组和对象永远不会存储在栈上,因为栈帧中只保存引用,这个引用
指向对象或者数组在堆中的位置
3. 方法结束后,堆中对象不会马上被移除,仅在垃圾收集的时候才会被移除
4. 堆,是GC执行的重点区域
3. 内存细分
- 逻辑上分为三部分: 新生代,老年代,元空间
新生代: Young Generation Space(Eden space, Survivor spaca)
老年代: Tenure Generation Space
元数据区:Meta Space
二、堆空间大小
1. 基本设置
- Java堆区用于存储Java对象实例,堆的大小在JVM启动的时候就用已经设定好了
# 1. 参数设置
-Xms:256k
1. 表示堆区的起始内存(新生代+老年代)
2. -X: jvm的参数
3. ms: memory start
-Xmx: 1028k
1. 表示堆区的最大内存
2. mx:memory max
# 2.异常
- 堆区的内存大小超过了-Xmx指定的最大内存时候, 就会抛出 OutOfMemoryError
OutOfMemoryError: Java heap space
# 3.最佳实践
-Xms和-Xmx配置相同的值? Yes!
-Xms1000M -Xmx1000M
能够在java垃圾回收机制处理完堆区后,不需要重新分隔计算堆区的大小,提高性能
(避免不必要的扩缩容,增大系统压力)
# 4. 默认情况
初始内存大小: 物理电脑内存大小/64
最大内存大小: 物理电脑内存大小/4
package com.nike.erick.d06;
public class Demo05 {
public static void main(String[] args) {
// 初始内存,
long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
// 最大内存
long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
System.out.println("初始JVM堆内存:" + initialMemory + "M");
System.out.println("最大JVM堆内存:" + maxMemory + "M");
System.out.println("本地物理内存:" + initialMemory * 64 / 1024 + "G");
System.out.println("本地物理内存:" + maxMemory / 1024 * 4 + "G");
}
}
2. 新生代和老年代
1. 存储在JVM中的java对象被划分为两类
1.1 生命周期短的瞬时对象,创建和消亡都很快
1.2 生命周期比较长,极端情况下和JVM的生命周期一样(Runtime类)
2. JVM堆区划分
2.1 年轻代: Eden, Survivor0和Survivor1(from区和to区)
2.2 老年代
2.1 内存大小
- 默认配置
- 一般不会去修改, 如果该项目中的很多的对象时间都很长,则考虑修改
- 大多数的java都是在Eden中被new出来的, 同时也会在Eden中被销毁
1. 新生代和老年代堆中比例
-XX:NewRation=2: 新生代占1,老年代占用2
-XX:NewRation=4: 新生代占1,老年代占用4
# 如何查看参数
jps : 得到端口号
jinfo -flag NewRatio 40402 : 得到比例
2. 新生代老年代按照指定数字分配
-Xmn100M 显示指定,以这个为准
3. 新生代中Eden 和另外两个Survivor默认比例是。 8:1:1
-XX:SurvivorRatio=8 :调整为 8:1:1
# 如何查看
jps : 得到端口号
jinfo -flag SurvivorRatio 40402 : 查看比例
2.2 对象分配过程
1. 新对象在Eden创建,如果满了(可达性算法),则触发 Minor GC(Young GC)
2. 回收不用的对象, 有用的对象复制到 S0中,并加上版本号
3. 第二次Eden满了后,继续触发 Minor GC
4. 将Eden中存活对象和S0的对象放到S1中,其中S0的也去判断哪些可用,可用的版本号加1
( 谁空放谁 )
5. from区到to区域时候,如果版本号达到15(阈值),则会Promotion, 放在老年代
-XX:MaxTenuringThreshold=15: 手动设置阈值
假如Survivor满了,同时没有达到阈值,也会放在老年代
tips: Survivor不会触发minor gc, 但是存在垃圾回收过程
- 特殊情况
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)