热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

Java垃圾回收机制(GC)1.1GC机制作用1.2堆内存3代分布(年轻代、老年代、持久代)1.3GC分类1.4GC过程Java应用内存问题分析2.1Java内存划分2.2Java



  1. Java垃圾回收机制(GC) 1.1 GC机制作用
    1.2 堆内存3代分布(年轻代、老年代、持久代)
    1.3 GC分类
    1.4 GC过程

  2. Java应用内存问题分析 2.1 Java内存划分
    2.2 Java常见内存问题
    2.3 ML(内存泄露) OOM(内存溢出)问题现象及分析
    2.4 IBM DUMP分析工具使用介绍

  3. Java应用CPU、线程问题分析


Java垃圾回收机制(GC)



1.GC机制作用


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


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


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




2.Java堆3代分布



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




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错误




Java应用内存问题分析方法



1.Java内存划分


可粗略划分三类:


1.1 堆内存


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




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


1.3 永久保存区、方法区(Permanent Generation)用于存储已被虚拟机加载的类信息、常量、静态变量等




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: Java heap 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<int[]> list = new ArrayList<int[]>();
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.内存泄露现象





heapspace:OutOfMemoryError





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


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


线程问题


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


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


jstack pid >> thread.dump




5.JAVA DUMP分析工具


IBM HeapAnalyzer:ha456.jar


IBM Thread and Monitor Dump Analyzer:jca457.jar


堆dump分析


占用内存较多代码块


分析代码快上下文


分析占用内存的对象内容





线程dump分析


活跃线程


阻塞线程


等待资源线程




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)行





3.程序无响应


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


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






推荐阅读
  • jvm内存区域与溢出为什么学习jvm木板原理,最短的一块板决定一个水的深度,当一个系统垃圾收集成为瓶颈的时候,那么就需要你对jvm的了解掌握。当一个系统出现内存溢出,内存泄露的时候 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 初识java关于JDK、JRE、JVM 了解一下 ... [详细]
  • 生产环境下JVM调优参数的设置实例
     正文前先来一波福利推荐: 福利一:百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。福利二 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • java中的try catch_Java中的trycatchfinally异常处理
    Java中的try-catch-finally异常处理一、异常处理异常(Exception):是在运行发生的不正常情况。原始异常处理:if(条件){处理办法1处理办法 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • JVM:33 如何查看JVM的Full GC日志
    1.示例代码packagecom.webcode;publicclassDemo4{publicstaticvoidmain(String[]args){byte[]arr ... [详细]
  • Java面试题系列:将面试题中比较经典和核心的内容写成系列文章持续在公众号更新,可巩固基础知识,可梳理底层原理,欢迎大家持续关注【程序新视界】。本篇为面试题系列第2篇。常见面试问 ... [详细]
  • 开发笔记:Python之路第一篇:初识Python
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Python之路第一篇:初识Python相关的知识,希望对你有一定的参考价值。Python简介& ... [详细]
  • 子类从父类继承所有的成员(字段,方法,嵌套类),构造方法不属于成员,所有子类不能继承,但是子类可以调用父类的构造方法对于private方法和属性,子类一定是继承了的,但是没有访问权 ... [详细]
author-avatar
郑谊099_448
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有