JVM内存(堆和非堆)jdk1.8

前言

1.8同1.7比,最大的差别就是:元数据区取代了永久代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元数据空间并不在虚拟机中,而是使用本地内存。

调试工具

arthas调试工具
https://alibaba.github.io/arthas/dashboard.html

查看堆内存
jmap -heap PID

查看一个进程有哪些内存映射
pmap -x PID

堆和非堆内存简介

堆和非堆均是在java虚拟机启动时创建。
Java 虚拟机具有一个堆(Heap),堆是运行时数据区域,所有类实例和数组的内存均从此处分配。JVM8中把运行时常量池、静态变量也移到堆区进行存储。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。

在JVM中堆之外的内存称为非堆内存(Non-heap memory)。由所有线程共享的方法区。方法区属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。

基本概念

(堆)Heap分为3个区,Young即新生代(分为Eden区、From Survivor、To Survivor三个区域,默认比例是8:1:1),Old即老生代。
Young保存刚实例化的对象。当该区被填满时,GC会将对象移到Old区。Permanent区则负责保存反射对象。
(非堆)MetaSpace:全称是MetaSpace,即方法区。用于存放Class和Meta信息,Class在被Load的时候被放入该区域。

堆内存分配

类型 默认值
初始分配的堆内存-Xms 物理内存的1/64
最大分配的堆内存-Xmx 物理内存的1/4
-XX:PermSize设置非堆内存初始值(jdk1.7) 物理内存的1/64
XX:MaxPermSize设置最大非堆内存(jdk1.7) 物理内存的1/4
-XX:MetaspaceSize初始元空间大小(jdk1.8) 21M
-XX:MaxMetaspaceSize最大元空间大小(jdk1.8) 没有限制

在这里插入图片描述

linux内存与jvm内存联系

我们经常会碰到这样一种情况,使用dashboard或者jmap查看到heap+noheap内存与top看到的内存大小不同。
RES(Resident Set Size)是常驻内存的意思,进程实际使用的物理内存
在这里插入图片描述
在这里插入图片描述
通过上图我们可以看到,RES占用了1.8g,heap+noheap占用了1.3g那么其余的0.6G内存去哪了呢?

当Java程序启动后,会根据Xmx为堆预申请一块保留内存,并不会直接使用,也不会占用物理内存
然后申请(malloc之类的方法)Xms大小的虚拟内存,但是由于操作系统的内存管理是惰性的,有一个内存延迟分配的概念。malloc虽然会分配内存地址空间,但是并没有映射到实际的物理内存,只有当对该地址空间赋值时,才会真正的占用物理内存,才会影响RES的大小。

所以可能会出现进程所用内存大于当前堆+非堆的情况

比如说该Java程序在5分钟前,有一定活动,占用了1.8G堆内存(无论堆中的什么代),经过GC之后,虽然堆内存已经被回收了,堆占用很低,但GC的回收只是针对Jvm申请的这块内存区域,并不会调用操作系统释放内存。所以该进程的内存并不会释放,这时就会出现进程内存远远大于堆+非堆的情况。

至于Oracle文档上说的,Jvm可能会向操作系统释放内存,经过测试没有发现释放的情况。不过就算有主动释放的情况,也不太需要我们程序关心了。

参考文章:
JVM 老年代内存没办法回收了
https://blog.csdn.net/david_lua/article/details/102735551?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-4

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章