Java OOM系列(一)

来源:互联网 发布:java按钮单击事件 编辑:程序博客网 时间:2024/06/05 07:00

题记

从本科二年级开始学习java,到使用java编写桌面应用,再到使用java做web & Android,及至现在Java已经作为我的主要工作语言,细数起来差不多有5年时间。Java是一个很全面很强大的语言,而我是一个很懒的人,懒到只想跟大家分享Java的某些东西。。。再加上,3个月前,确确实实遇到了一次线上的OOM问题,经过3个月的遗忘,就想跟大家分享一下平时都可能遇到的OOM问题以及可能可以通用的解决方法。

这个系列也是我写的第一个系列文章,大概可能应该分成3篇来写(有可能懒癌一犯只写一篇…也有可能写了5篇),第一篇主要是想简单介绍一下Java内存模型;第二篇介绍几个命令和工具,能够用在排查OOM问题上;第三篇就细分各种OOM问题,并归纳出我觉得可行的解决方法


Java内存模型简介

首先,为什么要介绍内存模型。遇到一个问题,首先我们应该先分析问题,找到问题的根本原因,然后才能从根本上解决问题。OOM问题,全称是OutOfMemoryError,即内存溢出错误,内存为什么会溢出?如果想弄清楚内存为什么会溢出,首先应该弄明白的是Java是怎么在管理内存的,Java程序在启动时内存是如何分配加载的,以及我们的每一行代码在执行的时候对内存会产生什么样的影响,如此才能真正清楚内存溢出的原因。我记得原来有一位C/python的同事,基本没有使用过java,但是在面试java程序员时,通常一个问题就可以帮助他筛选掉大部分的面试者:Java会不会内存泄漏?

其次,Java是分版本的,同样的问题,在不同版本的java中可能是不同的。所以,Java程序一般都是需要分版本对待的。内存模型也是如此,现在基本都在使用的是java 6以上版本,java 6和java 7的内存模型基本一致,java 8和java 7有稍微差别。下文主要介绍java 6 & 7,然后再简述java 8和他们的差别。

一般可以认为Java的内存模型主要包括寄存器、堆内存、栈内存、常量池、代码段、全局数据段。堆:存放所有new出来的对象;栈:存放基本类型的变量数据和对象的应用,对象(new出来的对象)本身并不存在栈中,而是存放在堆中或者常量池中(字符串常量对象存放在常量池中);常量池:存放基本类型常量和字符串常量;代码段: 用来存放从硬盘上读取的源程序代码; 全局数据段: 用来存放static定义的静态成员或全局变量。内存溢出可能是任何一种内存的溢出,如堆内存的溢出、栈内存的溢出、常量池的溢出等。经常遇到的还是堆和栈的溢出。

Java管理的堆内存主要分为Young Generation, Old Generation 和 Permanent Genetation。

有必要简单讲一下内存的垃圾回收机制,java的GC(Garbage Collection)算法有很多,比如引用计数法、tracing算法、compacting算法、copying算法、generation算法等,总的来说可以简单理解为Java的垃圾回收有两种,一种是Young Gen经常发生的回收,另一种是三种Gen同时发生的 Full GC。第二种发生是说三个内存不够使用了,需要释放内存。Fucc GC消耗很大,而且JVM可能会短暂性暂停工作。如果一个Java进程高频率的发生Full GC,那么这个进程的性能必定不会高,而且很有可能伴随OOM。
堆主要用来存放对象的,栈主要是用来执行程序的。栈内存的溢出,经常指的是线程栈的溢出,线程在执行的时候,线程栈是有大小的,当线程执行时线程栈大小超过了预设的值,会报StackOverFlow错误。当线程数创建过多,超过栈空间大小,导致线程创建失败时,会报OOM错。

大概清楚了Java虚拟机的内存结构,那么再遇到OOM错误时,只需要找出到底是哪个内存部分导致的溢出,基本就可以定位到代码的问题,从而解决掉OOM问题。推荐周志明老师的《深入理解Java虚拟机》这本书,这里面对于Java的内存模型、垃圾回收等讲解的很详细易懂。

最后,Java 8中去掉了 Perm Gen,所以不会出现 Perm Gen的溢出,多出来了一个新内存–元空间(Metaspace),大部分类元数据都在本地内存中分配,默认情况下,类元数据只受可用的本地内存限制(容量取决于是32位或是64位操作系统的可用虚拟内存大小)。对于僵死的类及类加载器的垃圾回收将在元数据使用达到“MaxMetaspaceSize”参数的设定值时进行,持续的元空间垃圾回收说明,可能存在类、类加载器导致的内存泄漏或是大小设置不合适。虽然Java 8的内存结构和之前的内存结构存在少许差异,但是遇到OOM问题时,查问题的方法是差不多的。

我觉得程序员的工作,本质是使用coding的方式来解决各种问题,这个问题可能是你想实现一种行为的自动化,也可能是一个Web,亦或者是集群的弹性伸缩等。解决问题的过程,就需要用到工具,而Java语言就是一种工具,而且也仅仅是一种工具。工具无好坏,只有顺手不顺手和是否适合之分。

——————-我是微信公众号分割线—————-
这里写图片描述

0 0