1、JAVA内存区域与内存溢出

1.1、概述

Java中JVM提供了内存管理机制,Java虚拟机在执行Java程序的过程中会把内分分为不同的数据区,如图:

1.2、程序计数器

程序计数器是当前线程所执行的字节码的行号指示器,作用就是根据计数器的值获取下一条要执行的字节码指令。当执行的是java方法,则记录的是正在执行的虚拟机字节码指令的地址,如果是Native方法,则这个计数器的值为空。不存在任务OutOfMemoryError。

1.3、虚拟机栈

每个普通Java方法(除去Native方法)在执行的时候都会同时创建栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息,每个方法被调用直到完成的过程对应着栈帧在JVM栈中的入栈与出栈。其中局部变量表所需要的内存空间在编译器间完成分配。

跟虚拟机栈相关联的异常有两种:

  • StackOverflowError

线程请求的栈深度大于虚拟机允许的最大深度。

  • OutOfMemoryError

虚拟机栈扩展时无法申请到足够的内存。

1.4、本地方法栈

用于虚拟机执行Native方法,其他和本地方法栈相同。也会有StackOverflowError和OutOfMemoryError。

1.5、堆

虚拟机启动后创建堆,用于存放对象实例。堆时垃圾回收器的主要工作区域,主要分为新生代和老年代,新生代又可以细分为Eden空间、From Survivor空间、To Survivor空间。java程序启动时,可用-Xmx与-Xms控制堆的大小。如果堆中没有内存完成实例分配并且堆也无法扩展时会抛出OutOfMemoryError。

1.6、方法区

方法区主要存储类的元数据,如虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码,JDK1.8之前以永久代实现,JDK1.8之后使用元空间,而且元空间使用的是系统内存。如果无法申请内存时,会抛出OutOfMemoryError。

2、垃圾回收

2.1、如何判断对象已经死亡?

2.1.1、引用计数法

在对象中添加一个引用计数器,当有个地方引用时,计数器值 1,当引用失效时,计数器值-1。计数器为0的对象就是死亡的,但是这里有个问题:对象循环引用,两个对象互相引用着对方,导致它们的引用计数器不为0,于是无法通知GC回收。

2.1.2、GC Roots搜索

Java中采用的是GC ROOT搜索,思路就是通过一系列名为“GC Roots”的对象作为起点,从这些节点开始向下搜索,搜索中所走过的路径称为引用链,当GC Roots对某一对象不可达时,则证明此对象不可用。

GC Roots包括以下几种:

  • 栈帧中的本地变量表中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈Native方法引用的对象

2.2、垃圾收集算法

2.2.1、标记-清除算法

标记-清除算法分为两个阶段:

  • 标记:首先标记出所有需要回收的对象。
  • 清除:统一回收被标记的对象。

这个算法有连个缺点:

  1. 效率不高
  2. 会产生不连续的内存碎片
2.2.2、复制算法

复制算法的效率很高,其将可用内存按照容量划分为大小相等的两块,每次只使用其中的一块,当一块用完时,就将还存活的对象复制到另一块上面,然后清除掉使用过的内存空间。

这种算法很适合回收新生代,在新生代中分为Eden空间、From Survivor空间、To Survivor空间,一般分配的内存比例为8:1:1,当回收时,将Eden与From Survivor中还存活的对象一次性拷贝到To Survivor中,之后清理掉Eden与From Servivor空间,当To Survivor空间不够时,需要依赖老年代。

2.2.3、标记-整理算法

在老年代,对象的存活率比较高,所以标记-整理算法被提出来了,首先标记出要回收的对象,然后将所有存活的对象都向一端移动,然后直接清理掉死亡的对象:

2.2.4、分代收集算法

分代回收的思想就是根据对象的存活周期,将不同的内存划分为几块,根据每块内存的特点采用适当的收集算法,比如新生代采用复制算法,老年代采用标记-整理算法。

2.3、垃圾收集器

下图展示了7种不同分代的收集器,如果两个收集器之间存在连线,则表示可以搭配使用。

通过以下命令可以查看垃圾回收器信息:

java -XX: PrintCommandLineFlags -version

我的测试服务器结果:

-XX:InitialHeapSize=524503488 -XX:MaxHeapSize=8392055808 -XX: PrintCommandLineFlags -XX: UseCompressedClassPointers -XX: UseCompressedOops -XX: UseParallelGC
java version "1.8.0_152"
Java(TM) SE Runtime Environment (build 1.8.0_152-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)

可以看到使用的是:ParallelGC。

JVM参数对应关系:

下面简单介绍7中垃圾回收器:

2.3.1、Serial收集器

新生代单线程收集器,简单高效。

2.3.2、ParNew收集器

Serial收集器的多线程版本,除了在垃圾回收时使用多线程,其余都和Serial收集器相同。

2.3.3、Parallel Scavenge收集器

Parallel Scavenge收集器是并行的采用复制算法的新生代收集器,着重于系统的吞吐量,适合后台运算而不需要太多用户交互的任务。

2.3.4、Serial Old收集器

Serial Old是单线程的老年代垃圾收集器,使用标记-整理算法。具有简单高效的特点。

2.3.5、Parallel Old收集器

Parallel Old收集器是Parallel Scanenge的老年代版本,多线程垃圾回收,也是用标记-整理算法。

2.3.6、CMS收集器

CMS注重服务的响应时间,是基于标记-清除算法实现。具有并发收集、低停顿的特点。

2.3.7、G1收集器

Garbage First,基于标记-整理算法,其将整个Java堆(包括新生代和老年代)划分为多个大小固定的独立区域,并且跟踪这些区域里的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域。

3、CPU占用过高问题排查

3.1、 linux查看进程信息

top

3.2、查看进程占用cpu最多的线程

ps -mp 23967 -o THREAD,tid,time

3.3、线程ID转16进制

printf "%x\n" 23968

3.4、查看线程信息

jstack  23967  |grep -A  10  5da0

jstack 23967  |grep 5da0 -A 30

3.5、 查看进程的对象信息

jmap -histo:live 23967 | more

3.6、查看进程的GC情况

jstat -gcutil 23967 1000 100

参考

利用jmap和MAT等工具查看JVM运行时堆内存

JVM内存区域与垃圾回收的更多相关文章

  1. 浅析JVM内存区域及垃圾回收

    一.JVM简介 JVM,全称Java Virtual Machine,即Java虚拟机.以Java作为编程语言所编写的应用程序都是运行在JVM上的.JVM是一种用于计算设备的规范,它是一个虚构出来的计 ...

  2. Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

  3. JVM内存管理及垃圾回收【转】

    很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...

  4. JVM内存管理和垃圾回收机制介绍

    http://backend.blog.163.com/blog/static/20229412620128233285220/     内存管理和垃圾回收机制是JVM最核心的两个组成部分,对其内部实 ...

  5. 浅谈JVM内存分配与垃圾回收

    大家好,我是微尘,最近又去翻了周志明老师的<深入理解Java虚拟机>这本书.已经看了很多遍了,每次都感觉似乎看懂了,但没过多久就忘了.这次翻了第三章的垃圾收集器与内存分配策略,感觉有了新的 ...

  6. JVM内存分配与垃圾回收机制管理

    项目上线,性能优化有个重要组成就是jvm内存分配和垃圾回收机制的管理配置. 网上随便能搜到相关的具体步骤,以及内存中各种参数对应的意义,不再赘述. 干货就是直接抛出遇到的问题,以及如何解决的,再说说待 ...

  7. JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)

    转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...

  8. JVM的stack和heap,JVM内存模型,垃圾回收策略,分代收集,增量收集

    (转自:http://my.oschina.net/u/436879/blog/85478) 在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认 ...

  9. JVM内存管理及垃圾回收

    一.JVM内存的构 Java虚拟机会将内存分为几个不同的管理区,这些区域各自有各自的用途,根据不同的特点,承担不同的任务以及在垃圾回收时运用不同的算法.总体分为下面几个部分: 程序计数器(Progra ...

随机推荐

  1. ios 版本更新提示-硬更新/软更新

    实现: 强制更新:每次弹框 非强制更新:一天提示一次 代码如下: 步骤一: 将检测更新写到APPDelegate的applicationDidBecomeActive中 步骤二: 检测是否需要更新 步 ...

  2. C语言学习笔记之杂七杂八容易忽略的点(以后看到一直补充)

    1.变量名可以由 数字 字母 下划线 组成.数字不能用在开头 2.取余%:  只能是整数取余 3.sizeof是个关键字  不是函数 4.printf("%10d\n",a); 共 ...

  3. 10、Strategy 策略模式 整体地替换算法 行为型模式

    1.模式说明 策略模式比较好理解,就是将程序中用到的算法整体的拿出来,并有多个不同版本的算法实现,在程序运行阶段,动态的决定使用哪个算法来解决问题. 2.举例 排序算法的问题,假如我们的程序中需要对数 ...

  4. 【Mysql】SpringBoot_2.1.0+Druid_1.1.10 配置数据源监控服务Yml格式

    访问地址:localhost:8080/druid 按照这个方法和版本配置没问题 版本或高或低可能会出现不兼容 1.添加依赖 <dependency> <groupId>com ...

  5. C++/C socket编程

    目录 socket()函数 何为socket Internet套接字 流格式套接字SOCK_STREAM 数据报格式套接字SOCK_DGRAM TCP/IP协议族 创建套接字 加载套接字库 Windo ...

  6. 基于注解的DI

    目录 一.使用注解的步骤 二.@Component 三.@Value 四.@Autowired 五.@Qualifier 六.@Resource 七.XML和注解对比 通过spring的注解完成对ja ...

  7. 深度强化学习:Deep Q-Learning

    在前两篇文章强化学习基础:基本概念和动态规划和强化学习基础:蒙特卡罗和时序差分中介绍的强化学习的三种经典方法(动态规划.蒙特卡罗以及时序差分)适用于有限的状态集合$\mathcal{S}$,以时序差分 ...

  8. Gulp的安装及用法

    1.安装淘宝镜像 npm install cnpm -g --registry=https://registry.npm.taobao.org cnpm -v 2.生成项目描述文件 package.j ...

  9. Oracle 根据单元格内容不同来判断不同条件

    select xxx,xxx from xxx where decode(AAA,0,BBB,1,CCC)='12345' 如果AAA字段等于0则AAA=''12345' 否则如果BBB字段等于1则B ...

  10. hook框架-frida使用-APP在模拟器无法打开,用钩子去除限制

    app拿soul为例子 一.环境配置 #模拟器的frida服务为86 #frida-server-12.9.8-android-x86 adb push frida-server-12.9.8-and ...