JAVA内存泄露专题

合集下载

Java应用开发中的常见问题解决方案

Java应用开发中的常见问题解决方案

Java应用开发中的常见问题解决方案随着技术的不断进步和应用的普及,Java作为一种广泛应用的编程语言,也面临着各种各样的问题。

本文将就Java应用开发中的常见问题进行探讨,并提出相应的解决方案。

一、内存泄漏问题解决方案内存泄漏是Java应用开发中的常见问题,出现内存泄漏会导致应用程序消耗过多的内存,最终可能导致应用崩溃或运行缓慢。

下面是一些常见的解决方案:1. 及时释放资源:在编写Java代码时,需要确保在使用完资源后及时将其释放,比如关闭文件、数据库连接、网络连接等。

2. 避免使用全局变量:全局变量容易造成内存泄漏,因为它们的生命周期过长,如果不适时清理内存,就会一直存在于内存中。

3. 使用缓存:在处理大量数据时,可以考虑使用缓存来提高性能,但需要注意及时清理缓存,避免产生内存泄漏。

二、多线程同步问题解决方案在Java应用开发中,多线程同步是一个常见的问题。

多线程可能导致数据不一致、死锁等问题。

以下是一些常见的解决方案:1. 使用线程安全的类:Java提供了一些线程安全的类,比如Vector、Hashtable等,使用这些类可以避免多线程同时访问数据的问题。

2. 使用同步关键字:在需要同步的代码块上使用synchronized关键字,确保多线程在访问共享资源时的同步性。

3. 使用锁:Java中的锁机制可以帮助解决多线程同步的问题。

可以使用ReentrantLock、ReadWriteLock等来实现对临界区的控制。

三、性能优化问题解决方案在Java应用开发过程中,性能优化是一个重要的问题。

以下是一些常见的解决方案:1. 使用合适的数据结构和算法:在编写代码时,选择合适的数据结构和算法可以提高程序的性能。

比如使用HashMap代替ArrayList、使用快速排序代替冒泡排序等。

2. 减少内存使用:优化内存使用可以提高程序的性能。

可以避免创建过多的对象、及时释放不再使用的资源等。

3. 多线程并行处理:使用多线程可以提高程序的运行效率。

javaOOM内存泄漏原因及解决方法

javaOOM内存泄漏原因及解决方法

javaOOM内存泄漏原因及解决⽅法前⾔这篇⽂章主要介绍了java OOM内存泄漏原因及解决⽅法,⽂中通过⽰例代码介绍的⾮常详细,对⼤家的学习或者⼯作具有⼀定的参考学习价值,需要的朋友可以参考下⼀、什么是OOMOOM,全称“Out Of Memory”,翻译成中⽂就是“内存⽤完了”,当JVM因为没有⾜够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error⼆、为什么会OOM、出现的原因是什么为什么会没有内存了呢?原因不外乎有两点:①分配的少了:⽐如虚拟机本⾝可使⽤的内存(⼀般通过启动时的VM参数指定)太少。

②应⽤⽤的太多,并且⽤完没释放,浪费了。

此时就会造成内存泄露或者内存溢出。

三、解决办法① ng.OutOfMemoryError: Java heap space ——>java堆内存溢出,此种情况最常见,⼀般由于内存泄露或者堆的⼤⼩设置不当引起。

对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,⽽堆⼤⼩可以通过虚拟机参数-Xms,-Xmx等修改。

② ng.OutOfMemoryError: PermGen space ——>java永久代溢出,即⽅法区溢出了,⼀般出现于⼤量Class或者jsp页⾯,或者采⽤cglib等反射机制的情况,因为上述情况会产⽣⼤量的Class信息存储于⽅法区。

此种情况可以通过更改⽅法区的⼤⼩来解决,使⽤类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。

另外,过多的常量尤其是字符串也会导致⽅法区溢出。

③ ng.StackOverflowError ——> 不会抛OOM error,但也是⽐较常见的Java内存溢出。

JAVA虚拟机栈溢出,⼀般是由于程序中存在死循环或者深度递归调⽤造成的,栈⼤⼩设置太⼩也会出现此种溢出。

可以通过虚拟机参数-Xss来设置栈的⼤⼩以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

Java内存泄漏排查:常见导致内存泄漏的问题和排查方法

Java内存泄漏排查:常见导致内存泄漏的问题和排查方法

Java内存泄漏排查:常见导致内存泄漏的问题和排查方法Java内存泄漏是每个Java开发者都会遇到的一个问题。

尽管Java拥有垃圾回收机制,但是如果在代码中存在内存泄漏的问题,这些垃圾回收机制也无法解决。

本文将介绍一些常见导致Java内存泄漏的问题,并提供一些排查方法。

首先,我们需要了解什么是内存泄漏。

简单来说,内存泄漏指的是在程序中分配的内存空间无法被回收,导致内存的占用不断增加。

如果内存泄漏问题严重,最终会导致程序运行缓慢甚至崩溃。

常见导致内存泄漏的问题之一是对象的生命周期管理不当。

在Java中,如果一个对象被创建后,没有被及时释放,那么这个对象就会一直存在于内存中,从而导致内存泄漏。

这种情况通常发生在使用完对象后忘记调用`close()`或`dispose()`等释放资源的方法。

另一个常见的问题是静态集合类的使用不当。

在Java中,静态集合类(如`ArrayList`、`HashMap`等)是一种常见的数据结构,用于存储大量的数据。

然而,如果在使用完后不及时清理这些集合,就会导致内存泄漏。

这是因为静态集合类会一直持有对对象的引用,即使这些对象已经不再使用,也无法被垃圾回收。

此外,内存泄漏还可能发生在线程池的使用上。

线程池是一种常见的多线程处理方式,可以提高程序的性能。

然而,如果在使用完线程池后没有及时关闭,就会导致内存泄漏。

这是因为线程池中的线程会一直存在,即使任务已经执行完毕。

那么,如何排查Java内存泄漏问题呢?下面是一些常用的排查方法。

首先,可以使用Java内存分析工具,如Eclipse Memory Analyzer(MAT)或VisualVM等。

这些工具可以帮助我们分析内存使用情况,查找可能存在的内存泄漏问题。

通过分析内存堆转储文件,我们可以找到哪些对象占用了大量的内存,并且可以查看它们的引用链,从而找到可能的内存泄漏点。

其次,可以使用代码审查的方式来排查内存泄漏问题。

通过仔细检查代码,特别是对于生命周期管理不当的对象,我们可以找到一些潜在的内存泄漏问题。

JAVA内存泄露、溢出的检查方法、工具介绍

JAVA内存泄露、溢出的检查方法、工具介绍

JAVA内存泄露、溢出的检查⽅法、⼯具介绍问题发现:在我们运⾏的⼀个项⽬上线运营后发现运⾏两天左右就会报内存溢出,只有重启tomcat才能恢复服务,异常信息如下:ng.OutOfMemoryError: GC overhead limit exceededng.OutOfMemoryError: Java heap space原因分析:在此之前必须先介绍⼀下关于jvm的内存控制,JVM即java虚拟机,它运⾏时候占⽤⼀定的内存,其⼤⼩是有限定的,如果程序在运⾏时jvm 占⽤的内存⼤于某个限度,则会产⽣内存溢出,也就是“ng.outofmemoryerror”。

如果jvm内存的没有限度,并且有⽆限⼤的内存,那jvm就永远不会出现内存溢出了。

很明显⽆限的内存是不现实的,但是⼀般情况下我们程序运⾏过程所需要的内存应该是⼀个基础固定的值,如果仅是因为我们的项⽬所需内存超过了jvm设置内存值导致内存溢出,那么我们可以通过增⼤jvm的参数设置来解决内存溢出的问题。

详细处理可参考java jvm的如下参数设置:-Xms -Xmx -Xmn -Xss-Xms: 设置JVM初始内存,此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。

-Xmx:设置JVM最⼤可⽤内存。

-Xmn:设置年轻代⼤⼩,整个堆⼤⼩=年轻代⼤⼩+年⽼代⼤⼩+持久代⼤⼩.持久代⼀般固定⼤⼩为64m,所以增⼤年轻代后,将会减⼩年⽼代⼤⼩.此值对系统性能影响较⼤,Sun官⽅推荐配置为整个堆的3/8.-Xss:设置每个线程的堆栈⼤⼩.在相同物理内存下,减⼩这个值能⽣成更多的线程.但是操作系统对⼀个进程内的线程数还是有限制的,不能⽆限⽣成。

在jvm参数调试过程中,发现分配最⼤内存数超过1G后,仍然会产⽣内存溢出的现象,⽽估计其正常分配使⽤的内存应该不会超过1G,那么由此可以基本断定其存在内存泄露现象,也就是⼀些原来分配的不再使⽤的内存不能被java的垃圾回归所回收,导致不断占⽤原分配的内存⽽不释放,导致不断申请更多的内存直到超过内存设置⽽导致内存溢出。

掌握Java中的内存泄漏检测与优化

掌握Java中的内存泄漏检测与优化

掌握Java中的内存泄漏检测与优化Java是一种面向对象的编程语言,其通过自动内存管理机制,即垃圾回收机制,来自动管理内存分配和释放。

然而,即使在这种自动内存管理机制下,仍然存在内存泄漏的问题。

内存泄漏指的是在程序运行过程中,不再需要的内存没有被及时释放,造成内存资源的浪费。

本文将详细介绍Java中内存泄漏的概念、检测和优化方法。

一、内存泄漏的概念内存在Java中是通过new操作符来分配的,当一个对象不再被使用时,应该及时将其释放以便重新利用该内存空间。

然而,如果在程序中存在某些对象无法被垃圾回收机制释放的情况,就会导致内存泄漏。

常见的内存泄漏场景包括:1.长生命周期的对象持有短生命周期对象的引用:如果一个长生命周期的对象持有一个短生命周期对象的引用,并且在长生命周期对象不再使用时忘记了释放这个引用,就会导致内存泄漏。

2.静态变量持有对象的引用:如果一个对象被赋值给一个静态变量,并且在这个对象不再需要时没有将该引用置空,就会导致内存泄漏。

3.监听器、回调函数等资源没有正确释放:如果一个对象注册了某个监听器或回调函数,但在对象不再需要时忘记了注销该监听器或回调函数,就会导致内存泄漏。

4.缓存导致的内存泄漏:如果对一个大量的对象进行缓存,但在不再需要这些对象时没有清理缓存,就会导致内存泄漏。

5.循环引用:如果两个或多个对象之间形成了循环引用,并且这些对象都没有被其他对象引用,就会导致内存泄漏。

二、内存泄漏的检测方法1.内存泄漏分析工具:Java提供了一些用于检测内存泄漏的工具,例如JVisualVM、YourKit等。

这些工具可以通过分析堆内存中的对象引用关系,帮助我们查找可能存在的内存泄漏问题。

2.日志分析:通过分析应用程序的日志,查看是否存在内存占用过高的情况,以及内存占用是否随时间增长。

三、内存泄漏的优化方法1.及时释放资源:当一个对象不再需要时,应该及时将其引用置空,以便垃圾回收机制能够释放其占用的内存空间。

Java语言内存泄漏定位与避免

Java语言内存泄漏定位与避免

Java语言内存泄漏定位与避免Java语言是一种广泛被使用的编程语言之一,其强大的内存管理功能是开发者青睐的重要原因之一。

然而,像其他编程语言一样,Java语言也存在内存泄漏的问题。

内存泄漏是指在程序执行过程中,本应被回收的内存未能被释放,从而导致系统内存的不断增加,最终引发性能下降甚至系统崩溃的情况。

本文将介绍如何定位和避免Java语言中的内存泄漏问题。

一、Java语言中的内存泄漏Java语言通过垃圾回收(Garbage Collection)机制来自动管理内存,但是如果在代码中存在一些潜在问题,就有可能导致内存泄漏的发生。

下面列举了几种常见的Java内存泄漏情况:1. 对象的引用未及时释放:当一个对象的引用被赋给一个变量后,如果这个对象在执行过程中再也没有被引用到,但是没有显式地将其置为null,那么该对象就无法被垃圾回收机制回收,造成内存泄漏。

2. 集合类未正确使用:在使用集合类(如ArrayList、HashMap等)时,如果没有在适当的时候清除不再使用的元素或者没有调用集合的clear()方法,就有可能导致内存泄漏。

3. 静态集合类的使用不当:静态集合类的对象被所有类共享,如果在使用完后没有及时清空,那么对象中的元素将一直被引用,无法被回收,造成内存泄漏。

4. 资源未关闭:在操作一些资源对象(如文件、数据库连接等)时,如果没有适时关闭这些资源,将导致资源对象一直被引用,从而无法释放内存。

二、定位Java语言中的内存泄漏问题定位Java语言中的内存泄漏问题是解决该问题的第一步,下面介绍几个常用的方法。

1. 使用内存监控工具:Java提供了一些内存监控工具,如VisualVM、jconsole等,通过这些工具可以查看内存使用情况、垃圾回收情况,从而定位可能存在的内存泄漏问题。

2. 代码审查:仔细审查代码,找出可能存在内存泄漏的地方。

特别需要注意的是,查找是否有忘记释放资源、是否有未清理集合的情况。

java项目中遇到的问题案例

java项目中遇到的问题案例

一、背景介绍在Java项目开发过程中,经常会遇到各种各样的问题,这些问题可能涉及到代码编写、性能优化、技术选型等方方面面。

本文将结合实际项目经验,以案例的形式介绍在Java项目中可能遇到的问题,并对这些问题进行深入分析和解决方案的探讨。

二、问题案例一:内存泄漏问题描述:在一个长期运行的Java应用程序中,发现内存占用逐渐增加,并最终导致了内存溢出。

经过分析发现,在程序运行过程中,存在大量未及时释放的对象占用了大量的内存空间,从而导致了内存泄漏。

解决方案:1. 使用内存分析工具对程序进行分析,定位内存泄漏的具体位置。

2. 检查程序中的代码逻辑,确保对象在不再使用时能够及时被垃圾回收器回收。

3. 使用弱引用、软引用等方式管理对象的生命周期,避免长期占用内存。

三、问题案例二:性能瓶颈问题描述:在一个大型的Java项目中,发现程序在高并发情况下性能急剧下降,响应时间较长,甚至出现了请求超时的情况。

经过分析发现,系统中存在性能瓶颈,导致了系统无法满足高并发请求的需求。

解决方案:1. 使用性能分析工具对程序进行检测,找出性能瓶颈的具体位置。

2. 对程序中的关键模块进行性能优化,例如减少数据库查询次数、优化算法复杂度等。

3. 使用缓存技术对频繁访问的数据进行缓存,减少系统对数据库的访问压力。

四、问题案例三:线程安全问题描述:在多线程并发场景下,程序出现了数据错乱、数据丢失等问题,经过分析发现这是由于程序中存在了线程安全问题导致的。

解决方案:1. 对程序中的共享资源进行合理的加锁保护,确保多线程访问时能够保持数据的一致性。

2. 使用并发控制工具,如Java中的Concurrent包下的工具类来简化线程安全编程的复杂度。

3. 对程序进行多线程并发测试,发现潜在的线程安全问题并及时修复。

五、问题案例四:第三方组件使用问题问题描述:在集成第三方组件时,发现程序出现了各种各样的问题,如兼容性、性能、安全等方面的问题。

解决方案:1. 对第三方组件进行全面的评估和测试,确保其与现有系统的兼容性。

有效解决Java中常见的内存泄漏问题

有效解决Java中常见的内存泄漏问题

有效解决Java中常见的内存泄漏问题在Java编程中,内存泄漏是一个常见的问题。

这种情况会导致系统内存不断增长并最终导致应用程序的崩溃。

在这篇文章中,我们将讨论如何避免和处理Java中的内存泄漏问题。

一、什么是内存泄漏?内存泄漏指在软件程序中,由于程序员的疏忽、失误或程序设计的不合理等原因,导致在运行过程中分配的内存空间没有被有效地释放,使得一些可用的内存暂时或永久地无法被程序使用,导致系统内存的不断增加。

如果内存泄漏得不到及时的修复,则可能会导致系统崩溃。

二、Java中的内存泄漏在Java中,内存泄漏通常是由于程序员在某些情况下没能正确的释放其不再需要的对象所导致的。

Java有自动的垃圾回收机制,这使得内存泄漏可能不再像C++那样危险,但是程序员仍然需要注意对象管理。

下面是Java中常见的几种内存泄漏的情况:1. 长生命周期的对象持有短生命周期的对象的引用在Java中,短生命周期的对象比如线程、事件和定时器等通常比较小,而长生命周期的对象比如GUI组件、数据库连接等通常比较大。

如果这些长生命周期对象保持对短生命周期对象的引用,那么这些短生命周期对象就不能被垃圾回收,从而导致内存泄漏。

2. 静态变量引用对象当一个类的静态变量引用一个对象时,这个对象将会在应用程序运行的整个生命周期内一直存在。

如果这个对象不再需要,但是静态变量仍在引用它,那么这个对象就无法被垃圾回收,从而导致内存泄漏。

3. 软引用和弱引用的不正确使用在Java中,可以使用软引用或弱引用保留对象引用。

这些引用可以帮助开发人员编写高效的程序,但是如果不正确使用,也会导致内存泄漏。

软引用和弱引用只有在被访问时才能保持引用,但是如果一个对象不再被访问,同时又被软引用或弱引用保留,那么这个对象将会被认为是垃圾而被回收。

三、避免内存泄漏的方法1. 及时释放资源程序员应该及时地释放他们分配的资源,特别是一些明确需要关闭的资源,如文件和数据库连接。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

内存泄露与内存溢出1定义1、内存泄漏:一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而造成那部分内存不可用的情况。

2、内存溢出:指内存不够使用而抛出异常,内存泄露是其形成的原因之一。

2危害会导致新的资源分配请求无法完成,引起系统错误,最后导致系统崩溃。

3内存泄漏分类4 内存泄露/溢出发生的区域5内存溢出异常6内存溢出常见原因7发生内存泄露的情形Java内存泄露根本原因是什么呢?答:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。

具体主要有如下几大类:7.1 静态集合类引起内存泄露像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放,因为他们也将一直被Vector等引用着。

例:解析:在这个例子中,循环申请Object 对象,并将所申请的对象放入一个Vector 中,如果仅仅释放引用本身(o=null),那么Vector 仍然引用该对象,所以这个对象对GC 来说是不可回收的。

因此,如果对象加入到Vector 后,还必须从Vector 中删除,最简单的方法就是将Vector对象设置为null。

7.2创建过大对象以上代码运行时瞬间报错。

7.3监听器在java 编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。

7.4 各种连接比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。

对于Resultset 和Statement 对象可以不进行显式回收,但Connection 一定要显式回收,因为Connection 在任何时候都无法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。

但是如果使用连接池,情况就不一样了,除了要显式地关闭连接,还必须显式地关闭Resultset Statement 对象(关闭其中一个,另外一个也会关闭),否则就会造成大量的Statement 对象无法释放,从而引起内存泄漏。

这种情况下一般都会在try里面去的连接,在finally里面释放连接。

7.5 内部类和外部模块等的引用内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。

此外程序员还要小心外部模块不经意的引用,例如程序员A 负责A 模块,调用了B 模块的一个方法如:public void registerMsg(Object b);这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,这时候就需要注意模块B 是否提供相应的操作去除引用。

7.6 单例模式不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露8JVM监控分析8.1查看系统资源的基本使用情况8.2查看内存使用情况8.3典型内存泄露堆内存情况9内存溢出/泄露实战9.1模拟Java堆溢出说明:Java堆用于存储对象实例,只要不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。

通过设置参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析。

代码清单1 Java堆内存溢出异常测试如果是内存泄露,可进一步通过工具查看泄露对象到GC Roots的引用链。

于是就能找到泄露对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收它们的。

掌握了泄露对象的类型信息及GC Roots引用链的信息,就可以比较准确地定位出泄露代码的位置。

如果不存在泄露,换句话说,就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx与-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

以上是处理Java堆内存问题的简单思路,处理这些问题所需要的知识、工具与经验是后面3章的主题。

9.2虚拟机栈和本地方法栈溢出JMV并不区分虚拟机栈和本地方法栈,栈部分通常会出现两种异常:1、如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

2、如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

代码清单2 虚拟机栈和本地方法栈OOM测试(因为每个方法压入栈的帧大小并不是一样的,所以只能说在大多数情况下)达到1000~2000完全没有问题,对于正常的方法调用(包括递归),这个深度应该完全够用了。

但是,如果是建立过多线程导致的内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程。

如果没有这方面的处理经验,这种通过“减少内存”的手段来解决内存溢出的方式会比较难以想到。

代码清单2-5 创建线程导致内存溢出异常9.3运行时常量池溢出如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。

该方法的作用是:如果池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String 对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量,如代码清单2-4所示。

代码清单2-4 运行时常量池导致的内存溢出异常运行结果:从运行结果中可以看到,运行时常量池溢出,在OutOfMemoryError后面跟随的提示信息是“PermGen space”,说明运行时常量池属于方法区(HotSpot虚拟机中的永久代)的一部分9.4方法区溢出方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。

对于这些区域的测试,基本的思路是运行时产生大量的类去填满方法区,直到溢出。

虽然直接使用Java SE API也可以动态产生类(如反射时的GeneratedConstructorAccessor和动态代理等),但在本次实验中操作起来比较麻烦。

在代码清单2-8中,笔者借助CGLib直接操作字节码运行时生成了大量的动态类。

值得特别注意的是,我们在这个例子中模拟的场景并非纯粹是一个实验,这样的应用经常会出现在实际应用中:当前的很多主流框架,如Spring、Hibernate,在对类进行增强时,都会使用到CGLib这类字节码技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载入内存。

另外,JVM 上的动态语言(例如Groovy等)通常都会持续创建类来实现语言的动态性,随着这类语言的流行,也越来越容易遇到与代码清单2-8相似的溢出场景。

代码清单2-8 借助CGLib使方法区出现内存溢出异常9.5本机直接内存溢出DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值(-Xmx指定)一样,代码清单2-9越过了DirectByteBuffer类,直接通过反射获取Unsafe实例进行内存分配(Unsafe类的getUnsafe()方法限制了只有引导类加载器才会返回实例,也就是设计者希望只有rt.jar 中的类才能使用Unsafe的功能)。

因为,虽然使用DirectByteBuffer分配内存也会抛出内存溢出异常,但它抛出异常时并没有真正向操作系统申请分配内存,而是通过计算得知内存无法分配,于是手动抛出异常,真正申请分配内存的方法是unsafe.allocateMemory()。

代码清单2-9 使用unsafe分配本机内存10内存溢出预防与解决办法10.1避免内存泄露/溢出措施1、尽早释放无用对象的引用;2、优化算法,减小空间复杂度。

3、尽量少用静态变量,因为静态变量是全局的,GC不会回收。

4、避免集中创建对象尤其是超大对象,如果可以的话尽量使用流操作。

5、尽量运用对象池技术以提高系统性能,例如连接池。

6、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。

7、优化配置10.2查看系统状态监控显示:10.3发现内存泄露通常情况下,内存问题的可能会表现为:1、运行一段时间后系统崩溃,报ng.OutOfMemoryError异常2、启动时直接崩溃,报错ng.OutOfMemoryError3、系统已经不能正常提供服务,但无错误日志4、系统运行正常,响应速度逐渐减慢为了分析判断内存问题,通常除了查看基本的系统状态信息外,还可以对内存、CPU、线程分别进详细分析。

例如:对内存堆DUMP进行分析,如下图所示:(报表清晰的显示发现内存泄露的个数)另外,还可以通过一些性能监测分析工具辅助分析,如 JProfiler、Optimizeit Profiler进行分析。

10.4定位内存泄露思路:1、查看线程独占的超长生命周期对象,及其代码调用关系2、查看占用空间较多的对象及其代码调用关系为解决内存泄露问题,一般需要Dump出内存快照转储文件,再通过内存映像分析工具(如Eclipse Memory Analyzer)对Dump出来的堆转储快照进行分析。

从上图信息可知,dump文件在位置:C:\Users\ADMINI~1\AppData\Local\Temp\visualvm.dat\localhost_368\heapdump-146491 9773882.hprof内存泄露的关键位置将dump文件导入eclipse中,经Eclipse Memory Analyzer分析,得出报表。

在Accumulated Objects by Class区域,可以看到垃圾对象占用内存空间的信息,如下如所示:由上图可以清晰的看到哪些类占用了内存空间,便可以进行响应代码查错与修改。

相关文档
最新文档