1.JVM内存结构
JVM按照运行时数据的存储结构来划分内存结构,不同格式的数据分别存储在不同的区域,统称为运行时数据,运行时数据包括Java程序本身的数据信息和JVM运行Java需要的额外数据信息。
JVM内存结构
Non-Heap
CodeCache
Permanent Generation space
Direct MomeryHeap
JVM GC管理
1.1 jvm运行时的数据区
线程私有:程序计数器、Java虚拟机栈、本地方法栈
线程公用:Java堆、方法区
1.2 jvm内存分配
栈内存分配
保存参数、局部变量、中间计算过程和其他数据。退出方法的时候,修改栈顶指针就可以把栈帧中的内容销毁。
栈的优点:存取速度比堆快,仅次于寄存器,栈数据可以共享。
栈的缺点:存在栈中的数据大小、生存期是在编译时就确定的,导致其缺乏灵活性。
堆内存分配
堆的优点:动态地分配内存大小,生存期不必事先告诉编译器,它是在运行期动态分配的,垃圾回收器会自动收走不再使用的空间区域。
堆的缺点:运行时动态分配内存,在分配和销毁时都要占用时间,因此堆的效率较低。
多线程的Java应用程序:
为了让每个线程正常工作就提出了程序计数器(Program Counter Register),每个线程都有自己的程序计数器这样当线程执行切换的时候就可以在上次执行的基础上继续执行,仅仅从一条线程线性执行的角度而言,代码是一条一条的往下执行的,这个时候就是Program Counter Register,JVM就是通过读取Program Counter Register的值来决定该线程下一条需要执行的字节码指令,进而进行选择语句、循环、异常处理等线程:
从OOP而言,相当于一个对象,该对象中具有执行代码,同时也有要处理的数据,数据包含Thread工作时候要访问的数据,同时也包含现在的Stack,在Stack中包含了Thread本地的数据,也包含了拷贝的全局数据;从面向过程的角度而言:线程 = 代码 + 数据Main Memory:全局共享内存空间
区域化管理的好处:分而治之,优化对象
2.JVM堆结构
2.1 JVM堆结构
2.2 jvm堆配置参数
-Xms初始堆大小
默认物理内存的1/64(<1GB),官方建议,可以按实际情况调整-Xmx最大堆大小
默认物理内存的1/4(<1GB),实际中建议不大于4GB一般建议设置 -Xms = -Xmx
避免每次在gc后,调整堆的大小,减少内存抖动,系统内存分配开销整个堆大小 = 年轻代大小 + 年老代大小 + 持久代大小
2.3 jvm新生代(young generation)
新生代 = 1个eden区 + 2个Survivor区(e+s0+s1)
-Xmn年轻代大小(1.4 or later)
-XX:NewSize,-XX:MaxNewSize(设置年轻代大小(for 1.3/14))
默认值大小为整个堆的3/8-XX:NewRatio
年轻代(放在Eden和两个Survivor区)与年老代的比值(除去持久代)Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。-XX:SurvivorRatio
Eden区与Survivor区的大小比值,设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10用来存放JVM刚分配的Java对象
2.4 jvm老年代(tenured generation)
老年代=整个堆- 年轻代大小 - 持久代大小
年轻代中经过垃圾回收没有回收掉的对象被复制到年老代
老年代存储对象比年轻代年龄大的多,而且不乏大对象
新建的对象也有可能直接进入老年代
大对象,可通过启动参数设置-XX:PretenureSizeThreshold=1024(单位为字节,默认为0)来代表超过多大时就不在新生代分配,而是直接在老年代分配
大的数据对象,切数组中无引用外部对象
老年代大小无配置参数
2.5 jvm持久代(perm generation)
持久代 = 整个堆 - 年轻代大小 - 老年代大小
-XX:PermSize -XX:MaxPermSize
设置持久代的大小,一般情况推荐把-XX:PermSize设置成XX:MaxPermSize的值为相同的值,因为永久代大小的调整也会导致堆内存需要触发fgc存储Class、Method元信息,其大小与项目的规模、类、方法的数量有关。一般设置为128M就足够,设置原则是预留30%的空间
永久代的回收方式
常量池中的常量,无用的类信息,常量的回帖很简单,没有引用了就可以被回收
对于无用的类进行回收,必须保证3点:
类的所有实例都已经被回收
加载类的ClassLoader已经被回收
类对象的Class对象没有被引用(即没有通过反射引用该类的地方)