关于java:JVM内存模型之程序计数器

31次阅读

共计 3134 个字符,预计需要花费 8 分钟才能阅读完成。

前言

一般来说 OOM 指老年代无奈回收,而对象在不停的增长时,即 JVM 内存严重不足时,会抛出 java.lang.OutOfMemoryError 谬误, 如果想设置程序主动 dump, 则须要动参数中指定 -XX:+HeapDumpOnOutOfMemoryError 来保留 OOM 时的 dump 文件

常见起因

  • <font color=”rgb(53, 179, 120)”> 内存调配过小 </font>,失常业务应用了大内存,比如说导出数据,1000 条数据曾经达到 500M,但 -Xmx 参数设置小于 500M
  • 对象被一直创立,却没有开释, 比如说 HttpClient 不必连接池,始终新建,却不敞开; 线程创立也一样
  • io 流操作文档没敞开流。
  • 往一个动态汇合变量里始终压栈。
  • 连贯没开释。
  • Java 队列没耗费。
  • 频繁 IO 操作大文件。开启大型文件或从数据库一次拿了太多的数据很容易造成内存溢出,所以在这些中央要大略计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值

备注:基本上就是内存资源不够,申请资源过大而且无奈开释

Java 内存模型

Eden Space 字面意思是伊甸园,对象被创立的时候首先放到这个区域,进行垃圾回收后,不能被回收的对象被放入到空的 survivor 区域。
Survivor Space 幸存者区,用于保留在 eden space 内存区域中通过垃圾回收后没有被回收的对象。Survivor 有两个,别离为 To Survivor、FromSurvivor,这个两个区域的空间大小是一样的。执行垃圾回收的时候 Eden 区域不能被回收的对象被放入到空的 survivor(也就是 To Survivor,同时 Eden 区域的内存会在垃圾回收的过程中全副开释),另一个 survivor(即 From Survivor)里不能被回收的对象也会被放入这个 survivor(即 To Survivor),而后 To Survivor 和 From Survivor 的标记会调换,始终保障一个 survivor 是空的。
Eden Space 和 Survivor Space 都属于新生代,新生代中执行的垃圾回收被称之为 Minor GC(因为是对新生代进行垃圾回收,所以又被称为 Young GC),每一次 Young GC 后留下来的对象 age 加 1。

Old Gen 老年代,用于寄存新生代中通过屡次垃圾回收依然存活的对象,也有可能是新生代调配不了内存的大对象会间接进入老年代。通过屡次垃圾回收都没有被回收的对象,这些对象的年代曾经足够 old 了,就会放入到老年代。
当老年代被放满的之后,虚构机会进行垃圾回收,称之为 Major GC。因为 Major GC 除并发 GC 外均需对整个堆进行扫描和回收,因而又称为 Full GC。
heap 区即堆内存,整个堆大小 = 年老代大小 + 老年代大小。堆内存默认为物理内存的 1 /64(<1GB);默认空余堆内存小于 40% 时,JVM 就会增大堆直到 -Xmx 的最大限度,能够通过 MinHeapFreeRatio 参数进行调整;默认空余堆内存大于 70% 时,JVM 会缩小堆直到 -Xms 的最小限度,能够通过 MaxHeapFreeRatio 参数进行调整。

官网参考:
Java 内存模型


这里分几局部,Heap Space(堆), Method Area(办法区),Navtive Area(本地区), Off Heap Space(堆外区)

堆内存寄存对象以及数组的数据,办法区寄存类的信息(包含类名、办法、字段)、动态变量、编译器编译后的代码,本地区蕴含线程栈、本地办法栈等寄存线程,办法区有时被称为长久代(PermGen)

Heap Space(堆)

  • 被所有线程共享
  • 存储数组与对象

Method Area(办法区)- JDK1.8 后为元空间

  • 被所有线程共享
  • 它存储已被 Java 虚拟机加载的类信息、常量、动态变量、即时编译器编译后的代码等,Code Cache 代码缓存区,它次要用于寄存 JIT 所编译的代码。CodeCache 代码缓冲区的大小在 client 模式下默认最大是 32m,在 server 模式下默认是 48m,这个值也是能够设置的,它所对应的 JVM 参数为 ReservedCodeCacheSize 和 InitialCodeCacheSize

本地区

  • 线程公有
  • 蕴含线程栈、本地办法栈等寄存线程

为了了解下面的阐明,举个例子

import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.Logger;

public class HelloWorld {private static Logger LOGGER = Logger.getLogger(HelloWorld.class.getName());

    public void sayHello(String message) {SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY");
        String today = formatter.format(new Date());
        LOGGER.info(today + ":" + message);
    }
}

Java GC 基本知识

主动垃圾收集是查看堆内存,辨认正在应用的对象和未应用的对象以及删除未应用的对象的过程。应用中的对象或援用的对象,意味着程序的某些局部依然保护着指向该对象的指针。程序的任何局部都不再援用未应用的对象或未援用的对象。因而,能够回收未援用对象应用的内存。

在像 C 这样的编程语言中,调配和勾销分配内存是手动过程。在 Java 中,垃圾回收器会主动解决开释内存的过程。根本过程能够形容如下。

回收过程官网介绍

在 Java 语言里,可作为 GC Roots 对象的包含如下几种:

a. 虚拟机栈 (栈桢中的本地变量表) 中的援用的对象 
b. 办法区中的类动态属性援用的对象 
c. 办法区中的常量援用的对象 
d. 本地办法栈中 JNI 的援用的对象


罕用定位问题命令

  • 首先定位到 java 程序的过程,用 jps 命令
jps 
jps -v

  • 查看存活对象占用状况
jmap -histo:live 1| head -20


对象阐明:

- B byte
- C char
- D double
- F float
- I int
- J long
- Z boolean
- [数组,如[I 示意 int[]
- [L+ 类名 其余对象

  • 生产对堆快照 Heap dump

jmap -dump:format=b,file=/tmp/ 过程号_jmap_dump.hprof 过程号

jmap -dump:live,format=b,file=/tmp/ 过程号_live_jmap_dump.hprof 过程号
  • jstat
#1s 一次,共 10 次
jstat -gcutil 1 1000  10

#额定输入上次 GC 起因
jstat -gccause 1

S0:幸存 1 区以后应用比例
S1:幸存 2 区以后应用比例
E:Eden Space(伊甸园)区应用比例
O:Old Gen(老年代)应用比例
M:元数据区应用比例
CCS:压缩应用比例
YGC:年老代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收耗费工夫
GCT:垃圾回收耗费总工夫

频繁 GC 问题或内存溢出问题

一、应用 jps 查看线程 ID
二、应用 jstat -gc 3333 250 20 查看 gc 状况,个别比拟关注 PERM 区的状况,查看 GC 的增长状况。三、应用 jstat -gccause:额定输入上次 GC 起因
四、应用 jmap -dump:format=b,file=heapDump 3333 生成堆转储文件
五、应用 jhat 或者可视化工具(Eclipse Memory Analyzer、IBM HeapAnalyzer、JProfiler)剖析堆状况。六、联合代码解决内存溢出或泄露问题。

死锁问题

一、应用 jps 查看线程 ID
二、应用 jstack 3331:查看线程状况

正文完
 0