JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)

JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)

加油站: 延迟满足感和即时满足感,显然前者更有利于将事情做到百分之二百的成效;

前言:

看各大公众号文章,很少对JVM有详细说明,应粉丝建议,接下来两篇文章先介绍下JVM基础,然后对JVM调优相关进行说明,最后对java区别C的垃圾回收机制相关算法进行说明,本篇文章是针对于JVM参数调优:JVM原理,内存区域说明,JVM参数配置,内存泄漏;
注:核心参考《深入理解java虚拟机》《java虚拟机规范》《揭秘java虚拟机》等相关书籍

正文:

Java虚拟机原理:

所谓虚拟机,就是一台虚拟的机器。他是一款软件,用来执行一系列虚拟计算指令,大体上虚拟机可以分为系统虚拟机和程序虚拟机, 大名鼎鼎的Visual Box、Vmare就属于系统虚拟机,他们完全是对物理计算的仿真,提供了一个可以运行完整操作系统的软件平台。

程序虚拟机典型代码就是Java虚拟机,它专门为执行单个计算程序而计算,在Java虚拟机中执行的指令我们成为Java字节码指令。无论是系统虚拟机还是程序虚拟机,在上面运行的软件都被限制于虚拟机提供的资源中。

Java发展至今,出现过很多虚拟机,起初Sun使用的一款叫ClassIc的Java虚拟机,到现在引用最广泛的是HotSpot虚拟机,除了Sum意外,还有BEA的Jrockit,目前Jrockit和HostSopt都被oralce收入旗下,大有整合的趋势。
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)

Java内存结构:

  1. 类加载子系统:负责从文件系统或者网络加载Class信息,加载的信息存放在一块称之方法区的内存空间。
  2. 方法区:就是存放类的信息、常量信息、常量池信息、包括字符串字面量和数字常量等。
  3. Java堆:在Java虚拟机启动的时候建立Java堆,它是Java程序最主要的内存工作区域,几乎所有的对象实例都存放到Java堆中,堆空间是所有线程共享。
  4. 直接内存:JavaNio库允许Java程序直接内存,从而提高性能,通常直接内存速度会优于Java堆。读写频繁的场合可能会考虑使用。
  5. 每个虚拟机线程都有一个私有栈,一个线程的Java栈在线程创建的时候被创建,Java栈保存着局部变量、方法参数、同事Java的方法调用、
    返回值等。
  6. 本地方法栈,最大不同为本地方法栈用于本地方法调用。Java虚拟机允许Java直接调用本地方法(通过使用C语言写)
  7. 垃圾收集系统是Java的核心,也是不可少的,Java有一套自己进行垃圾清理的机制,开发人员无需手工清理(下节详细介绍)。
  8. PC(Program Couneter)寄存器也是每个线程私有的空间, Java虚拟机会为每个线程创建PC寄存器,在任意时刻,一个Java线程总是在执行一个方法,这个方法称为当前方法,如果当前方法不是本地方法,PC寄存器总会执行当前正在被执行的指令,如果是本地方法,则PC寄存器值Underfined,寄存器存放如果当前执行环境指针、程序技术器、操作栈指针、计算的变量指针等信息。
  9. 虚拟机核心的组件就是执行引擎,它负责执行虚拟机的字节码,一般户先进行编译成机器码后执行。

堆、栈、方法区概念区别:

Java堆:
堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名,或者代号。

根据垃圾回收机制的不同,Java堆有可能拥有不同的结构,最为常见的就是将整个Java堆分为新生代和老年代。其中新声带存放新生的对象或者年龄不大的对象,老年代则存放老年对象。

新生代分为den区、s0区、s1区,s0和s1也被称为from和to区域,他们是两块大小相等并且可以互相角色的空间。

绝大多数情况下,对象首先分配在eden区,在新生代回收后,如果对象还存活,则进入s0或s1区,之后每经过一次

新生代回收,如果对象存活则它的年龄就加1,对象达到一定的年龄后,则进入老年代。
下面草图可以简单看下:
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)

Java栈:
Java栈是一块线程私有的空间,一个栈,一般由三部分组成:局部变量表、操作数据栈和帧数据区
局部变量表:用于报错函数的参数及局部变量
操作数栈:主要保存计算过程的中间结果,同时作为计算过程中的变量临时的存储空间。
帧数据区:除了局部变量表和操作数据栈以外,栈还需要一些数据来支持常量池的解析,这里帧数据区保存着访问常量池的指针,方便计程序访问常量池,另外当函数返回或出现异常时卖虚拟机子必须有一个异常处理表,方便发送异常的时候找到异常的代码,因此异常处理表也是帧数据区的一部分。
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)

Java方法区:
Java方法区和堆一样,方法区是一块所有线程共享的内存区域,他保存系统的类信息。
比如类的字段、方法、常量池等。方法区的大小决定系统可以保存多少个类。如果系统定义太多的类,导致方法区溢出。虚拟机同样会抛出内存溢出的错误。方法区可以理解为永久区。

虚拟机参数配置:
首先,什么是虚拟机参数配置:
在虚拟机运行的过程中,如果可以跟踪系统的运行状态,那么对于问题的故障排查会有一定的帮助,为此,在虚拟机提供了一些跟踪系统状态的参数,使用给定的参数执行Java虚拟机,就可以在系统运行时打印相关日志,用于分析实际问题。我们进行虚拟机参数配置,其实就是围绕着堆、栈、方法区、进行配置。

看到这里,大家可以说下熟悉那些jvm参数调优
堆的参数配置:
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
-XX:SurvivorRatio 用来设置新生代中eden空间和from/to空间的比例.
含以-XX:SurvivorRatio=eden/from=den/to

总结:在实际工作中,我们可以直接将初始的堆大小与最大堆大小相等,
这样的好处是可以减少程序运行时垃圾回收次数,从而提高效率。

-XX:SurvivorRatio 用来设置新生代中eden空间和from/to空间的比例.

设置最大堆内存:
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
设置新生代与老年代优化参数:
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
设置新生代比例参数:
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
设置新生与老年代代参数:
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
总结:不同的堆分布情况,对系统执行会产生一定的影响,在实际工作中,
应该根据系统的特点做出合理的配置,基本策略:尽可能将对象预留在新生代,减少老年代的GC次数。

除了可以设置新生代的绝对大小(-Xmn),可以使用(-XX:NewRatio)设置新生代和老年代的比例:-XX:NewRatio=老年代/新生代

内存溢出解决办法:

设置堆内存大小:

JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
设置栈内存大小:
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)

Tomcat内存溢出在catalina.sh 修改JVM堆内存大小:
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)
内存溢出与内存泄露的区别:
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
memory leak会最终会导致out of memory!

内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。

内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出.

以发生的方式来分类,内存泄漏可以分为4类

  1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
  2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
  3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
  4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

内存泄露总结:
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到;

总结:

本篇文章介绍了JVM原理,内存区域说明,JVM参数配置,内存泄漏等相关内容,主要是以java7版本说明,在向上版本中有部分相应改进,比如堆内存优化,以后会介绍相对于java7,其他版本的区别,关于相应JVM视频介绍,请关注回复小编获取资源及免费交流社区:
下节内容:垃圾回收机制及调优,感谢您的关注,精彩持续进行中。。。

因为有你,所以坚持,更多原创内容,关注微信公众号:十点攀程!
JVM参数调优-JVM原理,内存区域说明,JVM参数配置,内存泄漏总结(亲测有效)