JVM-堆

Heap 堆:是 JVM 内存中最大的一块,由所有线程共享,由垃圾回收器管理的主要区域,堆中对象大部分都需要考虑线程安全的问题

存放哪些资源

  • 对象实例:类初始化生成的对象,基本数据类型的数组也是对象实例,new 创建对象都使用堆内存
  • 字符串常量池:
    • 字符串常量池原本存放于方法区,JDK7 开始放置于堆中
    • 字符串常量池存储的是 String 对象的直接引用或者对象,是一张 string table
  • 静态变量:静态变量是有 static 修饰的变量,JDK8 时从方法区迁移至堆中
  • 线程分配缓冲区 Thread Local Allocation Buffer:线程私有但不影响堆的共性,可以提升对象分配的效率

堆内存相关

设置堆内存指令:-Xmx Size

内存溢出:new 出对象,循环添加字符数据,当堆中没有内存空间可分配给实例,也无法再扩展时,就会抛出 OutOfMemoryError 异常

堆内存诊断工具:(控制台命令)

  1. jps:查看当前系统中有哪些 Java 进程
  2. jmap:查看堆内存占用情况 jhsdb jmap --heap --pid 进程id
  3. jconsole:图形界面的,多功能的监测工具,可以连续监测

堆的划分

Java7 中堆内会存在年轻代、老年代和方法区(永久代)

  • Young 区被划分为三部分,Eden 区和两个大小严格相同的 Survivor 区。Survivor 区某一时刻只有其中一个是被使用的,另外一个留做垃圾回收时复制对象。在 Eden 区变满的时候,GC 就会将存活的对象移到空闲的 Survivor 区间中,根据 JVM 的策略,在经过几次垃圾回收后,仍然存活于 Survivor 的对象将被移动到 Tenured 区间
  • Tenured 区主要保存生命周期长的对象,一般是一些老的对象,当一些对象在 Young 复制转移一定的次数以后,对象就会被转移到 Tenured 区
  • Perm 代主要保存 Class、ClassLoader、静态变量、常量、编译后的代码,在 Java7 中堆内方法区会受到 GC 的管理,但是触发GC的时机比较晚,内存管理效率不高

分代原因:不同对象的生命周期不同,70%-99% 的对象都是临时对象,优化 GC 性能

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
// 返回Java虚拟机中的堆内存总量
long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
// 返回Java虚拟机使用的最大堆内存量
long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;

System.out.println("-Xms : " + initialMemory + "M");//-Xms : 245M
System.out.println("-Xmx : " + maxMemory + "M");//-Xmx : 3641M
}
文章作者: GeYu
文章链接: https://nuistgy.github.io/2023/05/31/JVM-堆/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yu's Blog