java 线程 内存溢出_Java常见问题分析(内存溢出、内存泄露、线程阻塞等)

Java垃圾回收机制(GC)

1.1  GC机制作用

1.2  堆内存3代分布(年轻代、老年代、持久代)

1.3  GC分类

1.4  GC过程

Java应用内存问题分析

2.1  Java内存划分

2.2  Java常见内存问题

2.3  ML(内存泄露) OOM(内存溢出)问题现象及分析

2.4  IBM DUMP分析工具使用介绍

Java应用CPU、线程问题分析

Java垃圾回收机制(GC)

1.GC机制作用

1.1 JVM自动检测和释放不再使用的对象内存

1.2 Java 运行时JVM会执行 GC,不再需要显式释放对象

例:Object.finallize()、 Windows.dispose()、 System.gc()

fb5cf1943e75c599e7f36b39ac347ab0.png

2.Java堆3代分布

b94a37ebc4675d4df4645379f2642c04.png

关于Java堆3代分布情况,可通过命令:jmap –heap pid 查看

f3b9edeec86bef7ca8128507ccfc1c86.png

3.GC分类

3.1 Young GC(Minor GC):收集生命周期短的区域(Young)

(1) 清空Eden+from survivor中所有no ref的对象占用的内存

(2) 将Eden+from survivor中所有存活的对象copy到to survivor中

(3) 一些对象将晋升到old中: to survivor放不下的或存活次数超过turning threshold中的

3.2 Full GC(Major GC):收集生命周期短的区域(Young)和生命周期比较长的区域(Old),对整个堆进行垃圾收集,有时也会回收持久区(Perm)

(1) 清空heap中no ref的对象

(2) 清空permgen中已经被卸载的class信息

4.GC过程

(1) 新生成的对象在Eden区完成内存分配

(2) 当Eden区满,再创建对象,会因为申请不到空间触发YGC,进行young(eden+1survivor)区的垃圾回收(为什么是eden+1survivor:两个survivor中始终有一个survivor是空的,空的那个被标记成To Survivor)

(3) YGC时,Eden不能被回收的对象被放入到空的survivor(也就是放到To Survivor,此时Eden被清空),另一个survivor(From Survivor)里不能被GC回收的对象也会被放入To Survivor,始终保证一个survivor是空的(YGC完成之后,To Survivor 和 From Survivor的标记互换)

(4) YGC结束后,若存放对象的survivor满,则这些对象被copy到old区,或者survivor区没有满,但是有些对象已经足够Old(超过XX:MaxTenuringThreshold),也被放入Old区

(5) 当Old区被放满的之后,进行完整的垃圾回收,即 FGC

(6) FGC后,若Survivor及old区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现OOM错误

013b8e9dfe5069412918498f4862bb1d.png

Java应用内存问题分析方法

1.Java内存划分

可粗略划分三类:

1.1 堆内存

存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理

ff927a72d05a78c7b7e979019751b630.png

1.2 栈内存

在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配(更准确地说是保存了引用的堆内存空间的地址,java中的“指针”)

1.3 永久保存区、方法区(Permanent Generation)

用于存储已被虚拟机加载的类信息、常量、静态变量等

94c27471649d20acc80c43f9156b605c.png

2.Java常见的内存问题表现形式:

2.1 OutOfMemory:内存溢出

2.2 Memory Leak:内存泄露

二者共同点:

(1) 通常最终的状态就会导致OOM错误

(2) 在Java堆或本地内存中都可能发生

二者不同点:

(1) ML是已经分配好的内存或对象,当不再需要,没有得到释放 而OOM则是没有足够的空间来供jvm分配新的内存块

(2) ML的内存曲线总体上是一条斜向上的曲线而OOM不是,反之未必

3.内存溢出类型:

虚拟机栈溢出、本地方法栈溢出、方法区溢出、堆溢出、运行时常量池溢出

异常类型:

(1) java.lang.OutOfMemoryError:  Javaheap space

堆内存溢出

优化:通过-Xmn(最小值)–Xms(初始值) -Xmx(最大值)参数手动设置 Heap(堆)的大小。

(2) java.lang.OutOfMemoryError: PermGen space

PermGen Space溢出(方法区溢出、运行时常量池溢出)

优化:通过MaxPermSize参数设置PermGen space大小。

(3) java.lang.StackOverflowError

栈溢出(虚拟机栈溢出、本地方法栈溢出)

优化:通过Xss参数调整

Demo代码 :

// Java 堆溢出

public static void main(String[] args) {

List list = new ArrayList();

while (true) {

list.add(new OOMObject());

}

}

static class OOMObject {

}

// 虚拟机栈溢出

public static void main(String[] args) {

// TODO Auto-generated method stub

System.out.println(add());

}

public static int add(){

return add();

}

// 方法区溢出

public static void main(String[] args) {

while (true) {

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(OOMObject.class);

enhancer.setUseCache(false);

enhancer.setCallback(new MethodInterceptor() {

@Override

public Object intercept(Object obj, Method method,

Object[] args, MethodProxy proxy) throws Throwable {

return proxy.invoke(obj, args);

}

});

enhancer.create();

}

}

static class OOMObject {

}

// 运行时常量池溢出

public static void main(String[] args){

// TODO Auto-generated method stub

List list = new ArrayList();

int i = 0;

while (true ){

list.add(String. valueOf(i++).intern());

}

}

// 内存泄露模拟

public static void main(String[] args) {

// TODO Auto-generated method stub

List list = new ArrayList();

Runtime run = Runtime.getRuntime();

int i=1;

while(true){

int[] arr = new int[1024];

list.add(arr);

if(i++ % 1000 == 0 ){

System.out.print("最大堆内存=" + run.maxMemory() / 1024 / 1024 + "M, ");

System.out.print("已分配内存=" + run.totalMemory() /1024 / 1024 + "M, ");

System.out.print("剩余空间内存=" + run.freeMemory() / 1024 / 1024 + "M, ");

System.out.println("最大可用内存=" + ( run.maxMemory() - run.totalMemory() + run.freeMemory() ) / 1024 / 1024 + "M");

sleep(1000);

}

}

}

public static void sleep(long time) {

try {

Thread.sleep(time);

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

4.内存泄露现象

cda18c1f50af54c0609eb0545985482e.png

heapspace:OutOfMemoryError

efd6fda6d2baa3c7328be576efee8d52.png

开发人员的分析、解决思路

内存对象申请未释放(未及时释放)

线程问题

分别从堆dump和线程dump进行分析:

jmap -dump:format=b,file=heap.dump pid

jstack pid >> thread.dump

5. javaDUMP分析工具

IBM HeapAnalyzer:ha456.jar

IBM Thread and Monitor Dump Analyzer:jca457.jar

堆dump分析

占用内存较多代码块

分析代码快上下文

分析占用内存的对象内容

ad1919f1a42367cfbbfd3305d8c5f41d.png

线程dump分析

活跃线程

阻塞线程

等待资源线程

a02e97e4b4cb0e92943d1d4244b1922a.png

Java应用CPU问题分析方法

1.程序响应慢,CPU高

(1) ThreadDump

jstack pid >> thread.dump

(2) 找到导致cpu高的线程 top -H -p pid

(3) pid 十进制转十六进制

http://tool.oschina.net/hexconvert/

(4) 找到对应的线程UE打开 threaddump文件查找:按十六进制关键字找到对应的线程,把相关的方法找出来,可以精确到代码的行号

2.程序响应慢,CPU不高

一般表现为thread struck在了i/o、db等

实例:

IO阻塞(程序表现为响应慢)

线程状态为“in Object.wait()”,说明正在等待线程池可用资源,由于线程池满导致新的IO请求处于排队等待状态,且发生在:at com.iflytek.diange.data.provider.sendsong.impl.SendSongImpl.getSendSongInfosByUserId(SendSongImpl.java:92)行

75986708bcde13920263b438fae77a46.png

3.程序无响应

死锁(程序表现为无响应)

线程状态为“waiting to lock”: 两个线程各持有一个锁,又在等待另一个锁,故造成死锁,且发生在DeadLockTest.java:39行

66f747b6cfe82f24cfdf3cfbd74bfc1f.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值