`
gqf2008
  • 浏览: 76748 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java内存分析、泄露、代码怎么更健壮

    博客分类:
  • java
阅读更多

一、内存溢出类型

1 java.lang.OutOfMemoryError: PermGen space

JVM 管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在 JVM 启动时创建;非堆是留给 JVM 自己用的,用来存放类的信息的。它和堆不同,运行期内 GC 不会释放空间。如果 web app 用了大量的第三方 jar 或者应用有太多的 class 文件而恰好 MaxPermSize 设置较小,超出了也会导致这块内存的占用过多造成溢出,或者 tomcat 热部署时侯不会清理前面加载的环境,只会将 context 更改为新部署的,非堆存的内容就会越来越多。

 

2 java.lang.OutOfMemoryError: Java heap space

第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间 ( -Xms) 是物理内存的 1/64 ,最大空间 (-Xmx) 是物理内存的 1/4 。如果内存剩余不到 40 %, JVM 就会增大堆到 Xmx 设置的值,内存剩余超过 70 %, JVM 就会减小堆到 Xms 设置的值。所以服务器的 Xmx Xms 设置一般应该设置相同避免每次 GC 后都要调整虚拟机堆的大小。假设物理内存无限大,那么 JVM 内存的最大值跟操作系统有关,一般 32 位机是 1.5g 3g 之间,而 64 位的就不会有限制了。

 

注意:如果 Xms 超过了 Xmx 值,或者堆最大值和非堆最大值的总和超过了物理内存或者操作系统的最大限制都会引起服务器启动不起来。

 

垃圾回收 GC 的角色

JVM 调用 GC 的频度还是很高的,主要两种情况下进行垃圾回收:

当应用程序线程空闲;另一个是 java 内存堆不足时,会不断调用 GC ,若连续回收都解决不了内存堆不足的问题时,就会报 out of memory 错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。

根据 GC 的机制,程序的运行会引起系统运行环境的变化,增加 GC 的触发机会。

为了避免这些问题,程序的设计和编写就应避免垃圾对象的内存占用和 GC 的开销。显示调用 System.GC() 只能建议 JVM 需要在内存中对垃圾对象进行回收,但不是必须马上回收,

一个是并不能解决内存资源耗空的局面,另外也会增加 GC 的消耗。

二、 JVM 内存区域组成

简单的说 java中的堆和栈

java把内存分两种:一种是栈内存,另一种是堆内存

1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;

2。堆内存用来存放由 new创建的对象和数组

在函数(代码块)中定义一个变量时, java就在栈中为这个变量分配内存空间,当超过变量的作用域后, java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由 java虚拟机的自动垃圾回收器来管理

 

堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。缺点就是要在运行时动态分配内存,存取速度较慢;

栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活 性。

 

java 堆分为三个区: New Old Permanent

GC 有两个线程:

新创建的对象被分配到 New 区,当该区被填满时会被 GC 辅助线程移到 Old 区,当 Old 区也填满了会触发 GC 主线程遍历堆内存里的所有对象。 Old 区的大小等于 Xmx 减去 -Xmn

 

java栈存放

栈调整:参数有 +UseDefaultStackSize -Xss256K,表示每个线程可申请 256k的栈空间

每个线程都有他自己的 Stack

 

三、 JVM如何设置虚拟内存

提示:在 JVM中如果 98%的时间是用于 GC且可用的 Heap size  不足 2%的时候将抛出此异常信息。

提示: Heap Size  最大不要超过可用物理内存的 80%,一般的要将 -Xms -Xmx选项设置为相同,而 -Xmn 1/4 -Xmx值。

提示: JVM初始分配的内存由 -Xms指定,默认是物理内存的 1/64 JVM最大分配的内存由 -Xmx指定,默认是物理内存的 1/4

默认空余堆内存小于 40%时, JVM就会增大堆直到 -Xmx的最大限制;空余堆内存大于 70%时, JVM会减少堆直到 -Xms的最小限制。因此服务器一般设置 -Xms -Xmx相等以避免在每次 GC  后调整堆的大小。

提示:假设物理内存无限大的话, JVM内存的最大值跟操作系统有很大的关系。

简单的说就 32位处理器虽然可控内存空间有 4GB,但是具体的操作系统会给一个限制,

这个限制一般是 2GB-3GB(一般来说 Windows系统下为 1.5G-2G Linux系统下为 2G-3G), 64bit以上的处理器就不会有限制了

提示:注意:如果 Xms超过了 Xmx值,或者堆最大值和非堆最大值的总和超过了物理内 存或者操作系统的最大限制都会引起服务器启动不起来。

提示:设置 NewSize MaxNewSize相等, "new"的大小最好不要大于 "old"的一半,原因是 old区如果不够大会频繁的触发 " " GC  ,大大降低了性能

 

JVM使用 -XX:PermSize设置非堆内存初始值,默认是物理内存的 1/64

XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的 1/4

 

 

解决方法:手动设置 Heap size

修改 TOMCAT_HOME/bin/catalina.bat

在“ echo "Using CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:

JAVA_OPTS="-server -Xms800m -Xmx800m -XX:MaxNewSize=256m"

 

 

四、性能检查工具使用

定位内存泄漏:

JProfiler 工具主要用于检查和跟踪系统(限于 Java 开发的)的性能。 JProfiler 可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视 JVM 运行情况及其性能。

1.  应用服务器内存长期不合理占用,内存经常处于高位占用,很难回收到低位;

2.  应用服务器极为不稳定,几乎每两天重新启动一次,有时甚至每天重新启动一次;

3.  应用服务器经常做 Full GC(Garbage Collection),而且时间很长,大约需要 30-40秒,应用服务器在做 Full GC的时候是不响应客户的交易请求的,非常影响系统性能。

 

因为开发环境和产品环境会有不同,导致该问题发生有时会在产品环境中发生, 通常可以使用工具跟踪系统的内存使用情况,在有些个别情况下或许某个时刻确实 是使用了大量内存导致 out of memory,这时应继续跟踪看接下来是否会有下降,

如果一直居高不下这肯定就因为程序的原因导致内存泄漏。

 

五、不健壮代码的特征及解决办法

1 、尽早释放无用对象的引用。好的办法是使用临时变量的时候,让引用变量在退出活动域后,自动设置为 null ,暗示垃圾收集器来收集该对象,防止发生内存泄露。

对于仍然有指针指向的实例, jvm 就不会回收该资源 , 因为垃圾回收会将值为 null 的对象作为垃圾,提高 GC 回收机制效率;

2 、我们的程序里不可避免大量使用字符串处理,避免使用 String ,应大量使用 StringBuffer ,每一个 String 对象都得独立占用内存一块区域;

String str = "aaa";

String str2 = "bbb";

String str3 = str + str2;// 假如执行此次之后 str ,str2 以后再不被调用 , 那它就会被放在内存中等待 Java gc 去回收 , 程序内过多的出现这样的情况就会报上面的那个错误 , 建议在使用字符串时能使用 StringBuffer 就不要用 String, 这样可以省不少开销;

 

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

4 、避免集中创建对象尤其是大对象, JVM 会突然需要大量内存,这时必然会触发 GC 优化系统内存环境;显示的声明数组空间,而且申请数量还极大。

这是一个案例想定供大家警戒

使用 jspsmartUpload 作文件上传 , 运行过程中经常出现 java.outofMemoryError 的错误,

检查之后发现问题:组件里的代码

m_totalBytes = m_request.getContentLength();

m_binArray = new byte[m_totalBytes];

问题原因是 totalBytes 这个变量得到的数极大,导致该数组分配了很多内存空间,而且该数组不能及时释放。解决办法只能换一种更合适的办法,至少是不会引发 outofMemoryError 的方式解决。参考: http://bbs.xml.org.cn/blog/more.asp?name=hongrui&id=3747

 

5 、尽量运用对象池技术以提高系统性能;生命周期长的对象拥有生命周期短的对象时容易引发内存泄漏,例如大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。

6 、不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。可以适当的使用 hashtable vector  创建一组对象容器,然后从容器中去取那些对象,而不用每次 new 之后又丢弃

7 、一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成  Out Of Memory Error  的状况,这时就大概要计算一下数据量的最大值是多少,并且设定所需最小及最大的内存空间值。

分享到:
评论

相关推荐

    JAVA内存泄漏分析工具

    Java内存泄漏分析是一个关键的系统优化任务,尤其是在大型企业级应用中,长期运行的系统可能会因为内存泄漏导致性能下降甚至服务中断。"JAVA内存泄漏分析工具"正是一款用于解决此类问题的专业工具,它能帮助开发者...

    Java内存泄露检测

    Java内存泄露检测是Java开发中一个关键的议题,因为它直接影响到程序的稳定性和资源效率。内存泄露是指程序中已分配的内存无法被正确地释放,从而导致系统资源的浪费和可能导致程序性能下降甚至崩溃。 首先,理解...

    java内存机制及异常处理

    Java内存机制是Java虚拟机(JVM)的关键组成部分,它管理着程序运行时的数据存储。在Java中,内存主要分为以下几个区域: ...正确理解和运用Java内存机制以及异常处理机制对于开发健壮、高效的Java应用程序至关重要。

    java内存分配 内存泄漏

    理解Java内存分配和JVM工作原理对于开发高效、健壮的Java应用至关重要。开发者应避免内存泄漏,合理使用内存,充分利用JVM的垃圾收集机制,同时理解JIT编译的优化策略,以提高程序的运行性能。在开发过程中,使用...

    Java加载dll,导致Java进程内存泄露

    在Java编程环境中,调用外部动态链接库(DLL)是一个常见的需求,特别是在需要与...在实际项目中,对本地代码进行充分的测试和调试,以及使用内存分析工具监控Java进程的内存使用情况,都是确保代码健壮性的重要环节。

    从 Java 代码到 Java 堆 理解和优化您的应用程序的内存使用

    【标题】:深入理解Java内存使用与优化:从代码到Java堆 【描述】:本文旨在帮助Java开发者深入了解从编写代码到Java堆的内存管理过程,以便更好地优化应用程序的内存使用。通过分析Java代码中的内存开销,以及讨论...

    jni层内存泄漏检测工具

    通过学习和使用这个库,开发者不仅可以解决当前的内存泄漏问题,还能提高对JNI内存管理的理解,从而编写更健壮的Android应用。 总结来说,JNI层内存泄漏检测工具LeakTracer是Android开发中的一个强大工具,它可以...

    4 种主流 Java 静态代码分析工具

    ### 4 种主流 Java 静态代码分析工具详解 #### 一、概述 静态代码分析工具在软件开发过程中扮演着重要的角色,特别是在提升代码质量和预防潜在问题方面。Java作为一种广泛使用的编程语言,拥有丰富的静态代码分析...

    深入Java核心_Java内存分配原理精讲

    总结,深入理解Java内存分配原理意味着深入理解Java运行机制,这将帮助开发者编写出更高效、更健壮的代码,提升系统的整体性能和稳定性。通过学习和实践,开发者可以更好地应对内存溢出、性能瓶颈等问题,从而成为...

    java内存模型文档

    这些文档如"Java内存模型.docx"、"Java内存模型2.docx"、"深入Java核心 Java内存分配原理精讲.docx"、"java内存模型.pdf"将深入探讨这些概念,帮助开发者更深入地理解Java内存模型及其在实际编程中的应用。...

    深入理解 Java 内存模型_程晓明_InfoQ_java_内存模型_

    Java内存模型,简称JMM(Java Memory ...总之,Java内存模型是Java多线程编程的基础,它为程序员提供了强大的工具来控制和保证并发代码的正确性。掌握JMM的相关知识,能够帮助我们写出更健壮、更高效的Java应用程序。

    java内存模型.pdf

    Java内存模型(JMM)是Java虚拟机...Java内存模型对于理解和编写高效、线程安全的代码至关重要。了解JMM的工作原理以及如何与其他编程概念(如同步和异步)交互,可以帮助开发者编写出更健壮、可移植的Java应用程序。

    JAVA编码习惯和几款JAVA性能分析工具

    2. **内存监控**:分析内存使用情况,检测内存泄漏和过度分配的问题。 3. **易用性**:工具应该直观,便于理解和使用,以便快速定位性能瓶颈。 常见的Java性能分析工具有JProfiler、VisualVM、YourKit Java ...

    java 内存泄露

    Java内存泄露:诊断与解决方案详解 一、Java内存泄露概览 Java内存泄露是指在Java应用程序运行过程中,已经不再使用的对象或数据结构由于某种原因未能被垃圾回收器(Garbage Collector,GC)回收,导致系统内存...

    java实现的内存分配

    总的来说,理解和掌握Java中的内存分配策略对于编写高效、健壮的代码至关重要。无论是轮转法还是高优先权法,都有其适用的场景,开发者可以根据具体需求选择合适的策略,并利用Java提供的工具和机制进行优化。在实际...

    Java中堆内存与栈内存分配浅析

    本文将深入探讨Java中堆内存与栈内存的分配机制,并通过对比分析它们之间的差异,帮助读者更好地掌握Java内存管理的核心概念。 #### 二、堆内存与栈内存概述 ##### 1. 堆内存 堆内存是Java虚拟机(JVM)用于存储...

    Java内存使用系列一Java对象的内存占用Java开发J

    这个“Java内存使用系列一Java对象的内存占用”主题旨在深入探讨Java对象在内存中的表现,以及如何有效地管理这些资源。Java开发人员需要理解内存分配、垃圾回收机制以及如何避免内存泄漏,以确保程序的高效运行。 ...

    java中带有不同构造方法的程序内存分析

    在Java编程语言中,内存管理是程序设计的重要组成部分。它涉及到对象的创建、存储和销毁,其中构造方法在这一过程中起着关键作用。...对于初学者来说,理解这些基础知识是编写高效、健壮的Java代码的关键。

    关于static的小结(Java内存溢出)

    ### 关于static的小结(Java内存溢出) #### 标题和描述中的知识点 在《关于static的小结(Java内存溢出)》这篇文章中,作者主要探讨了与Java中的`static`关键字相关的知识点,以及如何可能导致内存溢出的情况。...

    Java编程思想源代码及课后练习代码

    10. **垃圾收集与内存管理**:理解Java的自动内存管理和垃圾回收机制,可以避免内存泄漏和性能问题。 通过学习《Java编程思想》中的源代码和课后练习,你可以深入理解这些知识点,并通过实际操作提升编程技能。在...

Global site tag (gtag.js) - Google Analytics