1.1.JVM 运行时内存结构是怎样的?
答:
JVM 启动运行Class文件时会对JVM内存进行切分,我们可以将其分为**线程共享区**和**线程独享区**。
线程共享区:方法区和堆
线程独享区:栈和本地方法栈以及程序计数器
如图:
说明在JDK8中持久代(Permanent Generation)部分数据移到了元数据区(Metaspace),在JDK8中已经没有持久代。元空间的本质和永久代类似,都是对JVM规范中方法区的实现,不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小。
堆(Heap)里边有什么?
答:虚拟机启动时创建,被所有线程共享, 用于存放所有java对象实例.
可分为年轻代(eden)和老年代(Tenured)。
是垃圾收集器(GC)管理的主要区域
堆中没有内存分配时将会抛出OutOfMemoryError
1:JVM调优调堆内存大小:
-Xms设置堆的最小空间大小。
-Xmx设置堆的最大空间大小。
-XX:NewSize设置新生代最小空间大小。
-XX:MaxNewSize设置新生代最大空间大小。
-Xss:设置每个线程的堆栈大小。
在java中,菜鸡写的代码内存溢出很常见,当出现这种情况时,一是找出现问题的代码。看能否改正,如若不能可尝试调大JVM堆内存!
内存溢出错误:
2:JVM调优调方法区元数据区内存大小:
方法区(Method Area)里有什么?
方法区用来保存类的方法信息,2)不同jdk,方法区的实现不同,JDK8中的方法区对应的是Metaspace,是一块本地内存。
可以使用以下命令对有元数据区进行调整
-XX:MetaspaceSize 设置元数据区最小空间。 (JDK8)
-XX:MaxMetaspaceSize 设置元数据区最大空间。(JDK8)
3:JVM调优调GC算法
GC是什么?
垃圾回收机制是由垃圾回收器Garbage Collection来实现的。GC是后台的守护进程,它的特别之处是它是一个低优先级进程。但是可以根据内存的使用情况动态的调整他的优先级,因此,它是内存中低到一定程度时,才会自动运行,从而实现对内存的回收,这就是垃圾回收的时间不确定的原因。这个服务不是我们启动的是自动启动的。
程序运行期间,所有对象实例存储在运行时数据区域的heap中,当一个对象不再被引用(使用),他就需要被回收,在GC过程中,这些不需要被使用的对象从heap中回收,这样就会有空间循环被利用。
1、标记-清除算法
简单来说有两个步骤:标记、清除。
(1). 标记阶段:找到所有可访问的对象,做个标记
(2). 清除阶段:遍历堆,把未被标记的对象回收
缺 点
(1)因为涉及大量的内存遍历工作,所以执行性能较低,这也会导致“stop the world”时间较长,java程序吞吐量降低;
(2)对象被清除之后,被清除的对象留下内存的空缺位置会造成内存不连续,空间浪费。
2、标记整理(压缩)算法
标记-整理算法适合用于存活对象较多的场合,如老年代。它在标记-清除算法的基础上做了一些优化。
(1)、标记阶段:它的第一个阶段与标记/清除算法是一模一样的。
(2)、整理阶段:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。
优点
标记/整理算法不仅可以弥补标记/清除算法当中,内存区域分散的缺点,也消除了复制算法当中,内存减半的高额代价。
缺点
标记/整理算法唯一的缺点就是效率也不高。不仅要标记所有存活对象,还要整理所有存活对象的引用地址。从效率上来说,标记/整理算法要低于复制算法。
3、复制算法
复制算法简单来说就是把内存一分为二,但只使用其中一份,在垃圾回收时,将正在使用的那份内存中存活的对象复制到另一份空白的内存中,最后将正在使用的内存空间的对象清除,完成垃圾回收。
优点
复制算法使得每次都只对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
缺点
复制算法的代价是将内存缩小为原来的一半,这个太要命了。
三种算法比较:
效率:复制算法>标记-整理算法>标记-清除算法;
内存整齐度:复制算法=标记-整理算法>标记-清除算法
内存利用率:标记-整理算法=标记-清除算法>复制算法
调优策略:
新生代:由于存活的对象相对比较少,因此可以采用复制算法该算法效率比较快。
老年代:由于存活的对象比较多哈,可以采用标记-清除算法或是标记-整理算法。
JVM调优的常用工具:
1,jstack 用于生成java虚拟机当前时刻的线程快照
2,Memory Analyzer Tool(MAT)内存分析工具,可以帮助我们找到内存泄露,减少内存消耗。
总结:jvm调优,调堆内存,方法区内存,调GC算法!