#JVM内存分配
1.JVM内存分配
###1.1 栈内存分配
- 保存参数、局部变量、中间计算过程和其他数据。退出方法的时候,修改栈顶指针就可以把栈帧的内容销毁
- 栈的优点:存取速度比堆快,仅次于寄存器,栈数据可以共享
- 栈的缺点:存在栈中的数据大小、生存周期是在编译的时候指定的,导致其缺乏灵活性
###1.1 堆内存分配
- 堆的优点:动态地分配内存大小,生存期不必事先告诉编辑器,它是在运行期动态分配的,垃圾回收会自动的收走不再使用的空间区域
- 堆的缺点:运行时动态分配内存,在分配和销毁时都需要占用时间,因此堆的效率比较低
2.JVM堆结构
年轻代(Eden Survivor(from + to) )
老年代()
metadata()
为什么java这么分区?
3.JVM堆结构和垃圾回收
stop the world…
垃圾回收过程中是不会工作的~
4.JVM堆配置参数
-Xms 初始堆大小
默认物理内存的1/64(<1G)
-Xmx 最大堆大小
默认物理内存的1/4(<1G),实际中建议不大于4GB
一般建议设置 -Xms= -Xmx
好处是避免每次gc后,调整堆的大小,避免动态伸缩,减少系统的内存分配开销 内存泄露和内存溢出: 内存泄露也有可能是代码问题,也有可能是物理内存大小;
整个堆的大小=年轻代大小+年老代大小+metadata
4.JVM新生代(young generation)
1、新生代=1个eden区+2个survivor区
2、-Xmn 新生代大小(1.4版本或以后~)
默认值大小为整个堆的3/8
3、 -XX:NewRatio
年轻代(包括Eden和两个Survivor区)与年老代的比值(除去代)
Xms=Xmx并且设置了Xmn的情况下,该参数不需要设置4、-XX:SurvivorRatio
E区和Survivor区的大小比值,设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
5、 作用:用来存储JVM新分配的java对象
5.JVM老年代(tenured generation)
1、老年代=整个堆-年轻代大小-持久代大小
2、年轻代中经过垃圾回收没有被回收掉的对象,被复制到老年代
3、老年代存储对象比年轻代年龄大的多,而且不乏大对象
4、新建的对象也有可能直接进入老年代
1.大对象,可通过启动设置参数-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配 2.大的数组对象,且数组中无引用外部对象
5、老年代大小无配置参数
6.JVM持久代(perm generation)
1、持久代=整个堆-年轻代大小-年老代大小
2、-XX:PermSize -XX:MaxPermSize
设置持久代的大小,一般情况推荐把-XX:PermSize设置成-XX:MaxPermSize的值为相同的值。因为永久代大小的调整会导致内存需要触发fullgc
3、存放class、method元信息,其大小与项目的规模、类、方法的数量有关。一般设置为128M就足够,设置原则是预留空间的30%
4、持久代的回收方式
1.常量池中的常量,无用的类信息,常量的回收很简单,没有引用了就可以被回收
2.对于无用的类进行回收,必须保证3点:
类的所有实例都已经被回收
加载类的classloader已经被回收
类对象的class对象没有被引用(即没有提供反射引用该类的地方)