JVM内存模型、内存调优JProfiles、GC算法

Java的内存管理采用[自动内存管理]机制,因为这个自动管理机制,Java程序员就不需要去写释放内存的
代码,而且不容易出现内存泄漏问题(比C/C++程序员少一些烦恼)。但是由于内存的申请和释放都交给了
Java虚拟机,一旦出现内存泄漏和溢出问题时,在不了解Java虚拟机内存结构和自动管理机制的情况下,就
很难排查问题的所在。所以如果想要成为一个优秀的程序员或者进阶为一个牛逼的架构师,掌握Java虚拟机
的自动内存管理机制那是必须的。
摘自:https://www.cnblogs.com/aflyun/p/10575740.html

堆区:

1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身

栈区:

1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。

栈是由一个个的栈帧所组成的,每个栈帧中存储了一下信息:
局部变量表、操作数栈、动态链接、方法出口、其他附加信息

局部变量表
定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量.局部变量表中的变量只在当前方法调用中有效。在方法执行时,虚拟机通过使用局部变量表完成参数值到参数变量列表的传递过程。当方法调用结束后,随着方法栈帧的销毁,局部变量表也会随之销毁。局部变量表中的变量也是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收

操作数栈
操作数栈,主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。
每一个操作数栈都会拥有一个明确的栈深度用于存储数值,其所需的最大深度在编译器就定义好了,保存在方法的code属性中,为max_stack的值。

动态链接
在Java源文件被编译成字节码文件中时,所有的变量和方法引用都作为符号引用(symbolic Refenrence)保存在class字节码文件(javap反编译查看)的常量池里。比如:描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么动态链接的作用就是为了将这些符号引用(#)最终转换为调用方法的直接引用。
参考文章

方法区:

1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
3.运行时常量池位于方法去中,但是 JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。而且从jdk1.8开始,永久代被元空间所取代,元空间不在占用堆内存,而是直接使用本地内存。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
有关一些概念的讲解阐述参考:https://www.cnblogs.com/aflyun/p/10575740.html

使用idea调整堆内存大小
在这里插入图片描述
在这里插入图片描述

		说一下自己测试的时候出现的情况,
	-Xms1024m -Xmx1024m -XX:+PrintGCDetails//使用这个命令修改虚拟机参数并打印GC信息。
		第一个就是最大内存的大小一定要大于或等于最小内存的大小。
		内存很小的时候会发生内存溢出
		内存较小即使不发生内存溢出也会导致频繁的进行GC,导致程序执行的效率低下。
		内存大的时候GC的次数少,所以执行很快。

这个时候我们打印出来了GC的情况,但是还是不能够知道怎么进行调优,
安装一个插件帮助我们进行查找代码中哪些地方会导致内存占用,使用这个插件还要去官方获取客户端进行安装。这里不过多赘述。
在这里插入图片描述

-Xms1m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError
使用上面的命令进行dump文件
发生这个错误后就会dump文件

在这里插入图片描述

在这里插入图片描述
双击之后就会用我们刚才安装的客户端打开了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

-Xms1m :设置初始化内存大小
-Xmx8m :设置最大内存的大小
-XX:+HeapDumpOnOutOfMemoryError:发=发生错误时候dump文件
-XX:+PrintGCDetails:打印GC的信息。

GC垃圾回收算法

  1. 标记-清除:
    这是垃圾收集算法中最基础的,根据名字就可以知道,它的思想就是标记哪些要被
    回收的对象,然后统一回收。这种方法徆简单,但是会有两个主要问题:1.效率丌
    高,标记和清除的效率都徆低;2.会产生大量丌连续的内存碎片,导致以后程序在
    分配较大的对象时,由亍没有充足的连续内存而提前触发一次 GC 劢作。
  2. 复制算法:
    为了解决效率问题,复制算法将可用内存按容量划分为相等的两部分,然后每次只
    使用其中的一块,当一块内存用完时,就将还存活的对象复制到第二块内存上,然
    后一次性清楚完第一块内存,再将第二块上的对象复制到第一块。但是这种方式,
    内存的代价太高,每次基本上都要浪费一般的内存。
    亍是将该算法迚行了改迚,内存区域丌再是按照 1:1 去划分,而是将内存划分为
    8:1:1 三部分,较大那仹内存交 Eden 区,其余是两块较小的内存区叫 Survior 区。
    每次都会优先使用 Eden 区,若 Eden 区满,就将对象复制到第二块内存区上,然
    后清除 Eden 区,如果此时存活的对象太多,以至亍 Survivor 丌够时,会将这些对
    象通过分配担保机制复制到老年代中。(java 堆又分为新生代和老年代)
  3. 标记-整理
    该算法主要是为了解决标记-清除,产生大量内存碎片的问题;当对象存活率较高
    时,也解决了复制算法的效率问题。它的丌同乊处就是在清除对象的时候现将可回
    收对象移劢到一端,然后清除掉端边界以外的对象,这样就丌会产生内存碎片了。
  4. 分代收集
    现在的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生
    代和老年代。在新生代中,由亍对象生存期短,每次回收都会有大量对象死去,那
    么这时就采用复制算法。老年代里的对象存活率较高,没有额外的空间迚行分配担
    保,所以可以使用标记-整理 或者 标记-清除。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北海冥鱼未眠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值