JVM堆内存(heap)

Java堆内存管理是影响性能的主要因素之一。堆内存溢出是Java项目中非常常见的故障,在解决该问题之前,我们需要先了解一下什么是Java堆内存。

是什么

我们先来看一下,Java堆内存是如何划分的
JDK8之前

在这里插入图片描述

从JDK8开始,新生代与老年代更名(只是单纯的更名),无论哪个版本的JDK,其堆内存的划分都没有变化

废弃永久代

在JDK8版本废弃了永久代,替代的是元空间(MetaSpace),元空间与永久代上类似,都是方法区的实现,他们最大区别是:元空间并不在JVM中,而是使用本地内存。

为何移除永久代:
Ⅰ、Jrockit VM没有永久代,为了便于将HotSpot JVM与 JRockit VM合二为一,所以HotSpot JVM移除了永久代。

Ⅱ、方法区用于存放JVM加载的类的相关信息,但每个Java类的大小难以确定,永久代加载的类过多极易诱发java.lang.OutOfMemoryError:PermGen异常。
在这里插入图片描述

我们这里就分析一下JVM内存:

  • ① JVM内存分为堆内存和非堆内存,堆内存分为:new(新生代)+tenured(老年代),其可以通过参数 –Xms、-Xmx 来指定:–Xms用于设置初始分配大小,默认为物理内存的1/16;-Xmx用于设置最大分配内存,默认为物理内存的1/4。默认情况下,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为 1:2 ( 该值可以通过参数 –XX:NewRatio 来指定 ),即:新生代 ( Young ) = 1/3 的堆空间大小,老年代 ( Old ) = 2/3 的堆空间大小。
    下面来个代码示例:
public class Test{
 	//-Xms1024m -Xmx1024m -XX:+PrintGCDetails,该注释在Run Configurations中配置一下
 	public static void main(String[] args) {
  		System.out.println("Hello,JVM!");
 	}
}

在这里插入图片描述

控制台:total为新生代工作时内存空间大小,而非整个新生代内存空间大小。
在这里插入图片描述

  • ②新生代(new/young)被细分为Eden和Survivor两个区域,为了便于区分,两个Survivor区域分别被命名为from和to(可见上图控制台中to于from),默认情况下,Eden:from:to=8:1:1(可以通过参数–XX:SurvivorRatio来设定)。JVM每次只能使用Eden和其中一块Survivor区来为对象服务,所以无论什么时候,总有一块Survivor区是空闲着的,因此,新生代实际可用内存空间为90%(如上图控制台中,Eden加from或者to的space为新生代的total)。

工作原理以及分代概念

  • 新生成的对象首先放到新生代Eden区域中,当Eden空间满了,触发Minor GC(清理新生代)存活下来的对象复制移动到Survivor0区,Survivor0区满后触发执行Minor GC,survivor0区存活对象复制移动到Survivor1区,这样保证了一段时间内总有一个survivor区为空,经过多次Minor GC 之后依然存活的对象移动到老年区(old/tenured)。

  • JVM给每个对象设置了一个对象年龄(Age)计数器,每熬过一场Minor GC,对象年龄增加1岁,当它的年龄增加到阈值(默认为15,可以通过-XX:MaxTenuringThreshold 参数自定义该阀值),将被“晋升”到老年代。

  • 老年代存放长期存活的对象,占满后会触发Major GC(清理老年代) = Full GC(清理整个堆空间,包括另外两个代),GC期间会停止所有线程,等待GC完成,所以对响应要求高的应用应减少发生Major GC,避免响应超时。

为什么分代

将对象根据存活概率进行分类,对存活时间长的对象,放到固定区,从而减少扫描垃圾时间及GC频率,针对分类进行不同的垃圾回收算法,对算法扬长避短。

为什么survivor分为两块相等大小的幸存空间

主要为了解决碎片化。如果内存碎片化严重,也就是两个对象占用不连续的内存,已有的连续内存不够新对象存放,就会触发GC。

### 回答1: 可以通过以下命令查看JVM堆内存大小: 1. 使用jstat命令查看JVM堆内存使用情况: jstat -gc <pid> 其中,<pid>为Java进程的进程ID。 该命令会输出JVM堆内存的使用情况,包括堆内存的容量、已使用的空间、已提交的空间等信息。 2. 使用jmap命令查看JVM堆内存使用情况: jmap -heap <pid> 该命令会输出JVM堆内存的详细信息,包括堆内存的容量、已使用的空间、已提交的空间、垃圾回收器的信息等。 需要注意的是,使用jmap命令会暂停Java进程的运行,可能会影响应用程序的性能。因此,在生产环境中,建议使用jstat命令查看JVM堆内存使用情况。 ### 回答2: 在Linux系统中,要查看JVM堆内存大小,可以采用以下方法: 1.使用jps命令查看Java进程编号 jps命令可以列出当前在运行的Java进程编号,输入如下命令: jps 会输出所有正在运行的Java进程编号,找到需要查看的Java进程编号。 2.使用jmap命令查看堆内存使用情况 jmap命令可以生成当前Java进程的堆内存转储快照,输入如下命令: jmap -heap <Java进程编号> 例如,如果Java进程编号为12345,则输入如下命令: jmap -heap 12345 会输出该Java进程的堆内存使用情况,其中包括堆内存的大小、使用情况、垃圾回收情况等信息。 3.使用jstat命令实时查看堆内存使用情况 jstat命令可以实时查看Java进程的堆内存使用情况,输入如下命令: jstat -gc <Java进程编号> <时间间隔> <次数> 例如,如果Java进程编号为12345,时间间隔为1秒,次数为10次,则输入如下命令: jstat -gc 12345 1 10 会输出该Java进程的堆内存使用情况,其中包括堆内存的大小、使用情况、垃圾回收情况等信息,并每秒钟更新一次。 总之,Linux系统中可以通过jps、jmap、jstat等命令来查看Java进程的堆内存大小和使用情况,帮助用户优化Java程序的性能。 ### 回答3: 在Linux系统上,我们可以通过命令行来查看JVM堆内存大小。具体步骤如下: 1. 打开命令行终端,输入以下命令来检查是否已经安装了Java环境: ```shell java -version ``` 如果已经安装了Java环境,会显示出Java版本号等信息;否则需要先安装Java环境。 2. 运行JVM应用程序,使用jstat命令来查看堆内存使用情况: ```shell jstat -gc <pid> ``` 其中,<pid>是JVM的进程号,可以使用命令ps -ef | grep java来查找。在jstat命令输出中,我们可以看到类似下面的信息: ```shell S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT 1024.0 1024.0 0.0 701.0 8192.0 3331.8 26624.0 13705.5 20480.0 12483.9 24 1.809 2 0.562 2.371 ``` 在这里,我们关注OC列和OU列,它们分别表示老年代堆的容量和使用量。可以根据这两列的数据来计算老年代堆的使用率和空余内存大小,以及整个堆内存的使用率。 另外,我们还可以使用jmap命令来获取JVM内存信息,并导出堆内存的详细信息到文件中: ```shell jmap -heap <pid> jmap -dump:format=b,file=<path-to-dumpfile> <pid> ``` 同样,<pid>是JVM的进程号,<path-to-dumpfile>是导出文件的路径。使用jmap命令可以获取JVM中各个内存区域的使用情况、GC算法、线程堆栈等信息;使用jmap -dump命令可以导出当前JVM堆内存状态到文件中,以便于后续分析和调试。 通过以上方法,我们可以非常方便地查看Linux系统上JVM堆内存大小和使用情况,从而及时定位和解决JVM性能问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值