JVM---小白都能看懂的内存管理(有趣的图文教程)

1、内存如何划分、内存溢出的原因

创建对象new
JVM---小白都能看懂的内存管理(有趣的图文教程)_第1张图片
对象在内存中分布存储的数据结构
JVM---小白都能看懂的内存管理(有趣的图文教程)_第2张图片
对象访问方式(1、句柄池,2、直接指针)
JVM---小白都能看懂的内存管理(有趣的图文教程)_第3张图片
JVM---小白都能看懂的内存管理(有趣的图文教程)_第4张图片
JVM---小白都能看懂的内存管理(有趣的图文教程)_第5张图片

2、实战内存溢出

JVM---小白都能看懂的内存管理(有趣的图文教程)_第6张图片
JVM---小白都能看懂的内存管理(有趣的图文教程)_第7张图片
JVM---小白都能看懂的内存管理(有趣的图文教程)_第8张图片
这里可以参考之前的排查内存使用率高的时候的真实生产环境的一个案例场景
现在我们可以打开jdk自带的Jvisualvm(安装jdk目录bin下)
JVM---小白都能看懂的内存管理(有趣的图文教程)_第9张图片
dump堆转储文件,项目目录路径下。当然了你可以设置路径在刚才的第一步的时候参数添加
(dump文件路径)-XX:HeapDumpPath=/你的路径/logs
(dump文件可自定义名称) -XX:ErrorFile=/你的路径/logs/java_error_%p.log
JVM---小白都能看懂的内存管理(有趣的图文教程)_第10张图片
JVM---小白都能看懂的内存管理(有趣的图文教程)_第11张图片

打开文件以后如果现在你假设不知道你的应用代码哪里出现问题, 那么排查思路如下:一种是内存泄露,一种是内存设置过小。内存泄露则需要看GC roots的引用链。如果您还没有相关概念,可以点击这里,1分钟入门下jvm性能调优。如果是内存设置过小,那么我们可以按照物理机配置适当调到正常范围。
那么对于现在的问题,假设我想知道代码的一个内存使用情况,则如下走。
JVM---小白都能看懂的内存管理(有趣的图文教程)_第12张图片
JVM---小白都能看懂的内存管理(有趣的图文教程)_第13张图片
可以看到对象数组内存大小将近19M,我们的堆内存设置的是20M。那么我们需要点击该对象数组查看下具体代码引用情况
JVM---小白都能看懂的内存管理(有趣的图文教程)_第14张图片
可以看到的是该数组是在645编号实例中。无引用。一共创建了810325个对象,然后以每500为一个集合存放。
JVM---小白都能看懂的内存管理(有趣的图文教程)_第15张图片
OOMObject对象红框内的内容暂时先不说。基本上可以找到哪个对象是如何引用的,在哪里使用的对象占比比较大,代码需要优化。
JVM---小白都能看懂的内存管理(有趣的图文教程)_第16张图片
虚拟机栈和本地方法栈溢出,可以参考之前的点击这里,1分钟入门java内存分配

在这里需要提到的一点,就是内存换线程的思想。还是先看这个图。
JVM---小白都能看懂的内存管理(有趣的图文教程)_第17张图片

如果已经看过上面的两篇1分钟入门的文章基本对于这个图是有概念的

我们可以知道的是在运行内存中,我们根据大小可以归为堆和栈。其余可以忽略不计。那么每个栈是线程私有的,假设固定机器物理内存是8g,把代码区和数据区和本地机器使用的内存都去除掉。那么我们可控的只有堆的大小。分配最大堆的大小约小,这个时候我们的栈相对应可用空间就会增大,则创建线程数也可以随着可使用的栈的增多而数量增多。当然栈是有固定深度的,不是说你可以放无穷多的东西,所以如果使用递归的时候没有及时判出条件,或者使用的栈内存太大都会导致栈的溢出。

元空间和方法区,1.8+的话我们已经是元空间了,可以通过设置最大元空间和初始元空间来控制参数,具体根据应用class的大小来判定。但是元空间也不是无穷大的。受限于本机内存和使用内存后剩余的空间。
如果dump转储文件比较小,代码中使用了nio可以排查问题从直接内存(元空间大小或者方法区大小)导致的内存溢出。

你可能感兴趣的:(职场@虚拟机@Java)