当前位置:文档之家› Java程序里的内存泄漏是如何表现的

Java程序里的内存泄漏是如何表现的

Java程序里的内存泄漏是如何表现的
Java程序里的内存泄漏是如何表现的

Java程序里的内存泄漏是如何表现的

大多数程序员都知道使用类似于Java 的编程语言的好处之一就是他们无需再为内存的分配和释放所担心了。你只需要简单地创建对象,当它们不再为程序所需要时Java 会自行通过一个被称为垃圾收集的机制将其移除。这个过程意味着Java 已经解决了困扰其他编程语言的一个棘手的问题-- 可怕的内存泄漏。果真是这样的吗?

在进行深入讨论之前,让我们先回顾一下垃圾收集是如何进行实际工作的。垃圾收集器的工作就是找到程序不再需要的对象并在当它们不再被访问或引用时将它们移除掉。垃圾收集器从贯穿整个程序生命周期的类这个根节点开始,扫描所有引用到的节点。在遍历节点时,它跟踪那些被活跃引用着的对象。那些不再被引用的对象就满足了垃圾回收的条件。当这些对象被移除时被它们占用的内存资源会交还给Java 虚拟机(JVM)。

因此Java 代码的确不需要程序员负责内存管理的清理工作,它自行对不再使用的对象进行垃圾收集。然而,需要记住的是,垃圾收集的关键在于一个对象在不再被引用时才被统计为不再使用。下图对这一概念进行了说明。

上图表示在一个Java 程序执行时具有不同的生命周期的两个类。类A 首先被实例化,它存在的时间比较长,几乎贯穿整个进程的生命周期。在某个时间点,类B 被创建,类A 添加了一个对这个新建类的引用。我们假设类B 是某个用于显示并返回用户指令的用户界面部件。尽管类B 不再被使用,如果类A 对类B 的引用未被清除,类B 将继续存在并占据内存空间,即使下一次垃圾收集被执行。

什么时候需要注意内存泄漏?

如果在你的程序执行一段时间之后遇到https://www.doczj.com/doc/9b14415347.html,ng.OutOfMemoryError 的话,内存泄漏无疑是最值得怀疑的。除了这种明显的情况之外,什么时候需要考虑内存泄漏?完美主义的程序员会回答说所有的内存泄漏都需要进行审查和更改。然而,在跳到这一结论之前还需要考虑其他几点因素,包括程序的生命周期以及内存泄漏的大小。

考虑一下在一个程序的生命周期里垃圾收集器可能从未执行的情况。无法保证什么时候JVM 会调用垃圾收集-- 即使程序显式调用System.gc()。通常情况下,垃圾收集器不会自动运行,直到程序需要比目前可用内存还要多的内存。此时,JVM 会首先尝试调用垃圾收集器以获取更多可用内存。如果这个尝试仍旧不能够释放出足够的资源,JVM 将会从操作系统获取更多内存,直到达到所允许内存的最大值。

举个例子来说,一个小型的Java 应用程序,用来显示一些简单的配置修改的用户界面元素,出现了内存泄漏。垃圾收集器可能在程序关闭之前都不会被调用到,因为JVM 可能总是有足够的内存来创建程序所需要的所有对象。因此,在这种情况下,即便是一些已死对象在程序运行的时候仍旧占据着内存,但这并不影响实际应用。

如果开发中的Java 代码将以每天24 小时运行在服务器上,这时内存泄漏将会比上面的那个配置工具程序要明显的多了。即便是代码中最小的内存泄漏,在持续运行的情况下最终也将耗尽所有可用内存。

相反的情况下,即使一个程序只是短暂存活,却分配了大量临时对象(或者少量的占用大量内存的对象),在这些对象不再需要时没有取消引用,这样的Java 代码也会达到内存限制。

最后一个值得注意的问题是,不必过于担心(Java 程序所造成的)内存泄漏。Java 内存泄漏不应该被认为是像其他语言中所发生的那样危险,比如C++ 的内存丢失将永远不会返回给操作系统。Java 应用程序中,我们把不再需要的却占据着内存资源的对象都交给JVM.所以在理论上来说,一旦Java 程序和它的JVM 关闭掉,所有分配的内存都将归还给操作系统。

如何断定程序具有内存泄漏

查看一个运行在Windows NT 平台上的Java 程序是否具有内存泄漏,你可以简单地在程序运行的时候去观察任务管理器中的内存设置。然而,在观察一些运行中的Java 程序之后,你会发现,它们跟本地应用程序相比使用更多内存。我开发过的一些Java 项目会启用10 到20 MB 的系统内存。与这个数字相比,本地的操作系统自带的Windows Explorer 程序使用到5 MB.

另外一个关于Java 程序的内存使用要注意的是典型的运行在IBM JDK1.1.8 JVM 上的程序似乎在

其运行时不断吞噬了越来越多的系统内存。程序似乎永远不会返回一些内存给操作系统,直到一个非常大的物理内存分配给它。这会不会就是内存泄漏的迹象?

要明白是怎么回事,我们需要熟悉JVM 是如何将系统内存使用作自己的堆的。在运行java.exe 时,你可以使用一些特定的选项来控制垃圾收集的堆的启动容量和最大容量(分别是-ms 和-mx)。Sun 的JDK 1.1.8 默认使用1 MB 的启动设置和16 MB 的最大设置。IBM JDK 1.1.8 默认使用机器物理内存容量的一半作为最大设置。这些内存设置对JVM 发生内存溢出时的做法具有直接影响,这时JVM 可能会继续增长堆内存,而不是等待一个垃圾回收的结束。

因此为了寻找并最终消除内存泄漏,我们需要比任务监视程序更好的工具。当你想检测内存泄漏的时候内存调试程序(参见下文的参考资料)可以派上用场了。这些程序通常会给你关于堆内存里对象的数量、

每个对象实例的个数以及对象使用中的内存等一些信息。此外,它们还会提供很有用的视图,这些视图可以显示每个对象的引用和引用者,以便你跟踪内存漏洞的来源。

接下来,我将展示如何使用Sitraka Software 的JProbe 调试工具来检测和消除内存泄漏,希望会对你就如何部署这些工具并成功消除内存泄漏产生一些启发。

一个内存泄漏的例子

这个示例主要展示了我们部门开发的一个商业版应用的一个问题,这个问题在JDK 1.1.8 上工作了几个小时后被测试人员找出来。这个Java 应用程序的相关代码和包是由几个不同团队的程序员开发出来的。程序里出现的内存泄漏的原因,我怀疑,是由一些没有真正理解其他(团队)开发的代码的程序员所引起。讨论中的Java 代码允许用户不必去写Palm OS 本地代码来创建Palm 个人数码助理应用。通过使用图形界面,用户可以创建表单,使用控件对它们进行填充,然后连接控件事件来创建Palm 应用程序。测试人员发现,这个Java 应用最终发生了内存溢出--表单和控件的创建和删除延时。开发人员并没有发现这个问题存在,因为他们的机器(相对Palm)拥有着更多的物理内存。

为了讨论这个问题,我使用了JProbe 来断定问题的存在。即使拥有JProde 提供的强大工具和内存快照,调查仍然是一个繁琐的、反复的过程,它涉及先确定内存泄漏的原因,然后做出代码更改并验证其效果。

JProbe 有几个选项来控制在一次调试回话期间什么样的信息会被记录。经过一些试验后,我判定获取所需信息的最有效的方式是关掉性能数据收集,专注于捕获的堆数据。JProbe 提供了一个叫做运行时堆摘要的视图来显示Java 应用程序在一段时间内使用的堆内存的数量。它同时也提供了一个工具栏按钮用来在需要时强制JVM 执行垃圾收集--在想要看一下一个类的给定实例不再为Java 应用程序需要时是否会被垃圾收集,这个功能是很有用的。下图显示了在一段时间内使用的堆存储量。

在堆使用情况图中,蓝色部分表示已分配的堆空间量。我启动Java 程序之后它达到了一个稳定点,我强制垃圾收集器执行,这由绿线之前的蓝色曲线的一个骤降表示(这条绿线表示一个检查点被插入)。接下来,我先是添加而后删掉了四个表单并再次调用垃圾收集器。检查点之后的蓝色曲线的水平线比检查点之前的蓝色曲线的水平线高的事实告诉我们很可能出现了内存泄漏,因为该程序已经回归其只有一个简单可见的表单的初始状态。我检查实例确认了泄漏。总之,结果表明FormFrame 类(表单的主UI 类)的数量在检查点之后增加了四个。

寻找原因

要想将测试人员提交的问题隔离出来,第一步就是提供一些简单的、重复的测试用例。以上面那个例子为例,我发现简单地添加一个表单,删除这个表单,然后强制垃圾收集器的结果是一些关联到已经删除掉的表单的实例仍然存活着。这种问题通过JProbe实例摘要视图来看是显而易见的,视图中统计了堆内存中每个类的实例的个数。

要定位垃圾收集器工作时具体实例的引用,我使用了JProbe 的引用画面,如下图所示,来断定哪些类仍然在引用已被删除掉的FormFrame 类。这是调试这种问题的巧妙地方法之一,我通过它发现了很多不同的对象仍然在引用那些无用的对象。而通过试错来查明究竟是哪个引用者真正造成这个问题的过程却是相当耗时的。

在这个案例中,根类(左上角红色的那个)是出现问题的起源。右侧用蓝色突出的那个类就是追踪到的FormFrame 类。

对于这个具体的例子,找到的罪魁祸首是一个包含一个静态的哈希表的字体管理类。通过引用列表追踪后,我发现根节点是一个静态的哈希表,这个哈希表保存了每个表单使用的字体。各种表单可以被独立

地放大或缩小,所以哈希表包含了一个具有每个指定的表单的所有字体的向量。当表单的缩放视图改变时,带有字体的向量被获取并选择合适的缩放因素来适应字体大小。

这个字体管理器的问题是,在创建表单时,当代码将字体向量放进哈希表时,却没有定义表单删除时对向量的移除。因此,这个在整个应用程序的生命周期都存在的静态的哈希表,却从来没有移除指向每个表单的键值。所以,所有的表单和其相关联的类被遗留在了内存中。

问题修正

对于这个问题的简单解决方案就是字体管理器增加一个方法,来允许哈希表的remove() 方法会在用户删除表单时被调用到。增加的removeKeyFromHashtables() 方法如下所示:

public void removeKeyFromHashtables(GraphCanvas graph) {

if (graph != null) {

viewFontTable.remove(graph); // remove key from hashtable

// to prevent memory leak

}

}

然后,我在FormFrame 类里添加了对这个方法的一个调用。FormFrame 使用Swing 的内部框架来实现表单UI,因此对于字体管理器的调用被添加到当内部框架完全关闭时所执行的方法,如下所示:

/**

* Invoked when a FormFrame is disposed. Clean out references to prevent

* memory leaks.

*/

public void internalFrameClosed(InternalFrameEvent e) {

FontManager.get()。removeKeyFromHashtables(canvas);

canvas = null;

setDesktopIcon(null);

}

在我对代码做出修改以后,我使用调试工具来确认在相同的测试用例被执行时删除表单所关联到的对象的数目。

内存泄漏的防止

可以通过对一些常见问题的注意来防止内存泄漏。容器类,比如哈希表和向量,是找到引起内存泄漏的常见的地方。尤其是当这些类被声明为静态的并存活于应用程序的整个生命周期之中时。

另一个常见(导致内存泄漏的)问题是当你将一个类注册为事件监听器,却没考虑到当这个类不再需要时将其注销。还有,指向其他类的成员变量在恰当的时候要设置为null.

结束语

寻找内存泄漏的原因可能是一个繁琐的过程,还没有提到的一点是这将需要特殊的调试工具。然而,一旦你熟悉了追踪对象引用的工具和模式,你将能够跟踪内存泄漏。此外,你还会获得一些有价值的技能,不仅可以节省项目编程投入,而且在以后的项目中你将拥有找出可以防止发生内存泄漏的编程做法的眼光。

java技术面试必问:JVM 内存模型讲解

java技术面试必问:JVM 内存模型讲解 今天我们就来聊一聊Java内存模型,面试中面试官会通过考察你对jvm的理解更深入得了解你的水平。在了解jvm内存模型前我们先回顾下,java程序的执行过程: java文件在通过java编译器生产.class 字节码文件,然后由jvm中的类加载器加载各个类中的字节码文件,加载完成后由jvm执行引擎执行,在整个加载过程中,jvm用一段空间来存储程序执行期间需要的数据和相关信息,这个空间就叫做jvm内存。 一、JVM 的重要性 首先你应该知道,运行一个 Java 应用程序,我们必须要先安装 JDK 或者 JRE 。这是因为 Java 应用在编译后会变成字节码,然后通过字节码运行在 JVM 中,而 JVM 是JRE 的核心组成部分。 二、优点 JVM 不仅承担了 Java 字节码的分析(JIT compiler)和执行(Runtime),同时也内置了自动内存分配管理机制。这个机制可以大大降低手动分配回收机制可能带来的内存泄露和内存溢出风险,使 Java 开发人员不需要关注每个对象的内存分配以及回收,从而更专注于业务本身。 三、缺点 这个机制在提升 Java 开发效率的同时,也容易使 Java 开发人员过度依赖于自动化,弱化对内存的管理能力,这样系统就很容易发生 JVM 的堆内存异常、垃圾回收(GC)的不合适以及 GC 次数过于频繁等问题,这些都将直接影响到应用服务的性能。 四、内存模型 JVM 内存模型共分为5个区:堆(Heap)、方法区(Method Area)、程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)。 其中,堆(Heap)、方法区(Method Area)为线程共享,程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)为线程隔离。 五、堆(Heap) 堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。 堆被划分为新生代和老年代,新生代又被进一步划分为 Eden 区和 Survivor 区,最后 Survivor 由 From Survivor 和 To Survivor 组成。

JVM原理以及JVM内存管理机制

一、 JVM简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完成, 首先来说一下JVM工作原理中的jdk这个东西, .JVM 在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也就虚拟计算机. 操作系统装入JVM是通过jdk中Java.exe来完成。 通过下面4步来完成JVM环境. 1.创建JVM装载环境和配置 2.装载JVM.dll 3.初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例 4.调用JNIEnv实例装载并处理class类。 对于JVM自身的物理结构,我们可以从下图了解:

JVM的一个重要的特征就是它的自动内存管理机制,在执行一段Java代码的时候,会把它所管理的内存划分 成几个不同的数据区域,其中包括: 1. 程序计数器,众所周知,JVM的多线程是通过线程轮流切换并 分配CPU执行时间的方式来实现的,那么每一个线程在切换 后都必须记住它所执行的字节码的行号,以便线程在得到CPU 时间时进行恢复,这个计数器用于记录正在执行的字节码指令的地址,这里要强调的是“字节码”,如果执行的是Native方法,那么这个计数器应该为null; 2.

3. Java计算栈,可以说整个Java程序的执行就是一个出栈入栈 的过程,JVM会为每一个线程创建一个计算栈,用于记录线程中方法的调用和变量的创建,由于在计算栈里分配的内存出栈后立即被抛弃,因此在计算栈里不存在垃圾回收,如果线程请求的栈深度大于JVM允许的深度,会抛出StackOverflowError 异常,在内存耗尽时会抛出OutOfMemoryError异常; 4. Native方法栈,JVM在调用操作系统本地方法的时候会使用到 这个栈; 5. Java堆,由于每个线程分配到的计算栈容量有限,对于可能会 占据大量内存的对象,则会被分配到Java堆中,在栈中包含了指向该对象内存的地址;对于一个Java程序来说,只有一个Java堆,也就是说,所有线程共享一个堆中的对象;由于Java堆不受线程的控制,如果在一个方法结束之后立即回收这个方法使用到的对象,并不能保证其他线程是否正在使用该对象;因此堆中对象的回收由JVM的垃圾收集器统一管理,和某一个线程无关;在HotSpot虚拟机中Java堆被划分为三代:o新生代,正常情况下新创建的对象会被分配到新生代,但如果对象占据的内存足够大以致超过了新生代的容量限 制,也可能被分配到老年代;新生代对象的一个特点是最 新、且生命周期不长,被回收的可能性高;

JAVA内存分析指引201007_V0.2

JA V A内存分析指引 2010-07 1 环境说明 根据一般项目部署情况,生产环境以WebSphere5和WebSphere6为主,本文中所涉及环境变量也主要采用WebSphere的相关环境变量。 WebSphere5安装目录(默认): Windows:C:\Program Files\WebSphere\AppServer AIX:/usr/WebSphere/ AppServer WebSphere5日志路径 Windows:C:\Program Files\WebSphere\AppServer\logs\server1 AIX: /usr/WebSphere/ AppServer/logs/server1 WebSphere6安装目录(默认): Windows:C:\Program Files\IBM\WebSphere\AppServer AIX:/usr/IBM/WebSphere/AppServer WebSphere6日志路径: Windows:C:\Program Files\IBM\WebSphere\AppServer\profiles\AppSrv01\logs\server1 AIX: /usr/IBM/WebSphere/AppServer/profiles/AppSrv01/logs/server1 2 内存溢出原理 内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。 为了解决Java中内存溢出问题,我们首先必须了解Java是如何管理内存的。Java的内存管理就是对象的分配和释放问题。在Java中,内存的分配是由程序完成的,而内存的释放是由垃圾收集器(Garbage Collection,GC)完成的。 Java的内存垃圾回收机制是从程序的主要运行对象开始检查引用链,当遍历一遍后发现没有被引用的孤立对象就作为垃圾回收。GC为了能够正确释放对象,必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就是该对象不再被引用。

JVM调优与JAVA内存管理总结

JVM调优总结 基本回收算法 1.引用计数(Reference Counting) 比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。 2.标记-清除(Mark-Sweep) 此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。 3.复制(Copying) 此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。 4.标记-整理(Mark-Compact) 此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。 5.增量收集(Incremental Collecting) 实施垃圾回收算法,即:在应用进行的同时进行垃圾回收。不知道什么原因JDK5.0中的收集器没有使用这种算法的。 6.分代(Generational Collecting) 基于对对象生命周期分析后得出的垃圾回收算法。把对象分为年轻代、年老代、持久代,对不同生命周期的对象使用不同的算法(上述方式中的一个)进行回收。现在的垃圾回收器(从J2SE1.2开始)都是使用此算法的。 分代垃圾回收详述 如上图所示,为Java堆中的各代分布 Young(年轻代) 年轻代分三个区。一个Eden区,两个Survivor区。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以

java内存泄露定位与分析

使用IBM 性能分析工具解决生产环境中的性能问题(javacore) 上一篇 / 下一篇 2012-06-01 14:14:01 / 个人分类:javacore 查看( 655 ) / 评论( 0 ) / 评分( 0 / 0 ) https://www.doczj.com/doc/9b14415347.html,/developerworks/cn/java/j-lo-javacore/index.html 序言 企业级应用系统软件通常有着对并发数和响应时间的要求,这就要求大量的用户能在高响应时间内完成业务操作。这两个性能指标往往 决定着一个应用系统软件能否成功上线,而这也决定了一个项目最终能否验收成功,能否得到客户认同,能否继续在一个行业发展壮大 下去。由此可见性能对于一个应用系统的重要性,当然这似乎也成了软件行业的不可言说的痛——绝大多数的应用系统在上线之前, 项目组成员都要经历一个脱胎换骨的过程。 生产环境的建立包含众多方面,如存储规划、操作系统参数调整、数据库调优、应用系统调优等等。这几方面互相影响,只有经过不断 的调整优化,才能达到资源的最大利用率,满足客户对系统吞吐量和响应时间的要求。在无数次的实践经验中,很多软件专家能够达成 一致的是:应用系统本身的优化是至关重要的,否则即使有再大的内存,也会被消耗殆尽,尤其是产生OOM(Out Of Memory)的错 误的时候,它会贪婪地吃掉你的内存空间,直到系统宕机。 内存泄露—难啃的骨头 产生OOM 的原因有很多种,大体上可以简单地分为两种情况,一种就是物理内存确实有限,发生这种情况时,我们很容易找到原因,但是它一般不会发生在实际的生产环境中。因为生产环境往往有足以满足应用系统要求的配置,这在项目最初就是根据系统要求进行购 置的。 另外一种引起OOM 的原因就是应用系统本身对资源的的不恰当使用、配置,引起内存使用持续增加,最终导致JVM Heap Memory 被耗尽,如没有正确释放JDBC 的Connection Pool 中的对象,使用Cache 时没有限制Cache 的大小等等。本文并不针对各种情 况做讨论,而是以一个项目案例为背景,探索解决这类问题的方式方法,并总结一些最佳实践,供广大开发工程师借鉴参考。 项目背景介绍 项目背景: 1. 内网用户500 人,需要同时在线进行业务操作(中午休息一小时,晚6 点下班)。 2. 生产环境采用传统的主从式,未做Cluster ,提供HA 高可用性。 3. 服务器为AIX P570,8U,16G,但是只有一半的资源,即4U,8G 供新系统使用。 项目三月初上线,此前笔者与架构师曾去客户现场简单部署过一两次,主要是软件的安装,应用的部署,测一下应用是不是能够跑起来,算作是上线前的准备工作。应用上线(试运行)当天,项目组全体入住客户现场,看着用户登录数不断攀升,大家心里都没有底,高峰 时候到了440,系统开始有点反应变慢,不过还是扛下来了,最后归结为目前的资源有限,等把另一半资源划过来,就肯定没问题了。(须知增加资源,调优的工作大部分都要重新做一遍,系统级、数据库级等等,这也是后面为什么建议如果资源可用,最好一步到位的

基于java的学生信息管理系统设计与实现

基于java的学生信息管理系统设计与实现 基于java的学生信息管理系统设计与实现摘要:利用计算机进行学生信息管理,不仅能够保证准确、无误、快速输出,而且还可以利用计算机对有关信息进行查询,检索迅速、查找方便、可靠性高、存储量大、保密性好。本设计就是一个为实现信息化管理而开发的信息管理系统,能够进行信息存储、查询、修改等能功。该系统由六个模块构成,包括学生管理系统的主界面模块、学生信息管理模块、课程信息管理模块、成绩信息管理模块、信息查询模块和数据库操作模块。通过这些模块的有机结合,能方便的对学生信息进行综合管理,从而实现了信息化管理的目的。由于本人的能力有限,设计过程中难免有不足之处,设计中的存在问题本人将在日后进一步修改,以便让程序的设计更加完善。 关键词:oracle;异常处理;关系模型 目录

1 引言 1.1背景及意义 学生信息管理系统是一个教育单位不可缺少的部分。一个功能齐全、简单易用的信息管理系统不但能有效地减轻学校相关工作人员的工作负担,它的内容对于学校的决策者和管理者来说都至关重要。所以学生信息管理系统应该能够为用户提供充足的信息和快捷的查询手段。但一直以来人们使用传统人工的方式管理文件档案、统计和查询数据,这种管理方式存在着许多缺点,如:效率低、保密性差、人工的大量浪费;另外时间一长,将产生大量的文件和数据,这对于查找、更新和维护都带来了不少困难。随着科学技术的不断提高,计算机科学日渐成熟其强大的功能已为人们深刻认识,它已进入人类社会的各个领域并发挥着越来越重要的作用。 作为计算机应用的一部分,使用计算机对学校的各类信息进行管理,具有手工管理无法比拟的优点。例如:检索迅速、查询方便、效率高、可靠性好、存储量大、保密性好、寿命长、成本低等。利用计算机进行学生信息管理,不仅能够保证准确、无误、快速输出,而且还可以利用计算机对有关信息进行查询,检索迅速、查找方便、可靠性高、存储量大、保密性好。要科学地实现信息化管理,开发一个适合学校的,能够进行信息存储、查询、修改等功能的信息管理系统是十分重要的。这些优点能够极大地提高学校信息管理的效率,也是一个单位科学化、正规化管理,与世界接轨的重要条件。 本系统是将现代化的计算机技术和传统的教学、教务工作相结合,按照学院的工作流程设计完成的。通过一个简化的学生信息管理系统,使学生信息管理工作系统化、规范化、自动化,从而达到提高学生信息管理效率的目的。本课题就是针对便于学生信息管理的问题而设计的一个管理系统。 1.2 实验技术选择 本课题设计主要运用的技术有两个:java项目开发和oracle对数据库的操作。这里主要介绍本课题为什么选用这两个开发技术: ⑴首先了解一下Java语言特点

java内存空间详解

硬盘 heap stack Data code 内存 程序 操作系统代码 程序代码 New ,在堆里面为属性分配空间,初始化(String 默认值为null ) 声明的时候非配空间,初始值为null (局部变量,方法参数) 全局变量 存放程序所需要的代码 类变量,全局字符串,常量存放在数据段

Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java 在内存分配方面的知识。一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:存放用new产生的数据 ◆静态域:存放在对象中用static定义的静态成员 ◆常量池:存放常量

◆非RAM存储:硬盘等永久存储空间 Java内存分配中的栈 在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 Java内存分配中的堆 堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。引用变量就相当于是为数组或者对象起的一个名称。 引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。这也是Java 比较占内存的原因。 实际上,栈中的变量指向堆内存中的变量,这就是Java中的指针! 常量池(constant pool) 常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如: ◆类和接口的全限定名; ◆字段的名称和描述符; ◆方法和名称和描述符。 虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和

操作系统实验进程调度和内存管理java语言版本

源代码: 第一个类:divDTO publicclassdivDTO { privateintdivBase; privateintlength; privateintdivFlag; publicdivDTO(intdivBase,intlength,intdivFlag) { this.divBase=divBase; this.divFlag=divFlag; this.length=length; } publicdivDTO() { }

{ this.divBase=base; } publicintgetDivBase() { returnthis.divBase; } publicvoidsetLength(intlength) { this.length=length; } publicintgetLength() { returnthis.length; }

{ this.divFlag=flag; } publicintgetDivFalg() { returnthis.divFlag; } } 2.第二个类:PcbDTO publicclassPcbDTO { staticfinalintRunning=1; staticfinalintReady=2; staticfinalintWaiting=3; privateStringprocessName;

privateintrunTime; privateintprority; privateintprocessState; privateintbase; privateintlimit; privateintpcbFlag; publicPcbDTO(Stringname,inttime,intpro,intbase,intlimit) { this.processName=name; this.runTime=time; this.prority=pro; this.processState=0; this.limit=limit; this.base=base; } publicPcbDTO()

JAVA内存溢出解决方案

JAVA内存溢出 解决方案 1. 内存溢出类型 1.1. https://www.doczj.com/doc/9b14415347.html,ng.OutOfMemoryError: PermGen space JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。 PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。 一个最佳的配置例子:(经过本人验证,自从用此配置之后,再未出现过tomcat死掉的情况) set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m 1.2. https://www.doczj.com/doc/9b14415347.html,ng.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位的就不会有限制了。

飞加Java学习笔记_内存管理(1)

学习就要多问一些“为什么”和“怎么”,这样才有助于提高。这就是著名的5W2H 理论! 一、JAVA 内存管理机制概述 让我们先了解一下垃圾收集的工作原理。垃圾收集器的工作就是寻找那些不再被应用程序需要的对象,当它们不会再被访问或引用的时候清除它们。所以如果使用完变量后,最好将其马上置为null ,这样gc 才会认为它不会再被访问或引用。 本文将介绍Java 内存管理机制,并以int 变量和String 为例来,来讨论它们是如果使用内存的。 Java 内存分为栈(stack)与堆(heap),这两种都是由Java 自动来管理,程序员是不能通过编程来控制的。下面来介绍这两种内存: 堆(heap)内存:用于存放类的对象,如Data d1 = new Date(),d1是分配在堆内存中的,堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小。 栈(stack)内存:用于存放基本类型的变量,如int a = 5, a 是分配在栈内存中的,栈内存中的数据是可以共享。 二、JAVA 内存管理举例分析 1. Java 内存管理举例---int 变量 当在系统中声明一个int 变量时,系统做了哪些工作呢,如图1: 样例代码分析: 1. int a = 5; //新分配给5一段内存 2. int b = 6; //新分配给6一段内存 声明一个int 变量,如int age =20 将age 指向20, 不用再次分配内存分配一段内存给20,并将age 指向它 栈(stack)中有20这个值吗?

3. a = 7; //新分配给7一段内存, 存放5的那段内存将会被回收 第一行,在栈中创建一个a 的引用,然后在栈中搜索,看是否有3这个值,如果没有,就将3存在栈中,并且将a 指向3; 第二行,处理b ,如果在栈中有6这个值,那么直接让b 指向6,而不用再次分配内存;如果栈中没有6,那么需要在栈中再次开辟一段内存用于存储b 。 第三行,再处理a, 此时会在栈内存中重新检索,看有没有7这个值,如果有,那么将a 重新指向7;如果没有,则再开辟一段内存,然后将a 指向7。 2. Java 内存管理举例---String 对象 声明String 类的对象有两种方法,一种是new 一个对象,一种是直接将字符串赋给对象,下面将分别讨论两种方法的内存管理机制。 第一种方式:new ,如图2: 使用这种方式创建对象时,jvm 是不会主动把该对象放到strings pool 里面的,除非程序调用String 的intern 方法。 第二种方式:直接赋值,如图3: 样例代码分析: 1.String s1 = new String("Beijing"); 2.Stirng s2 = "Beijing"; 如String s1 = “飞加”; 则返回已有的String 对象给用 户,而不会在heap 中重新创建一 个新的String 对象jvm 则在堆(heap)中创建新的String 对象,将其引用返回给s1,同时将该引用添加至strings pool 中 在strings pool(由栈负责维护)中有“飞加”吗? Yes(有) No(无)如String s1 = new String(“飞加”); JVM 直接在堆(heap)中分配一段内存给“飞加”,并将 s1指向它。而不会管在堆(heap)中是否已经有“飞加” 图2 图3

JAVA内存泄露专题

内存泄露与内存溢出 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正常回收,导致内存泄露

java内存模型

12.Java内存模型 (原本准备把内存模型单独放到某一篇文章的某个章节里面讲解,后来查阅了国外很多文档才发现其实JVM内存模型的内容还蛮多的,所以直接作为一个章节的基础知识来讲解,可能该章节概念的东西比较多。一个开发Java的开发者,一旦了解了JVM内存模型就能够更加深入地了解该语言的语言特性,可能这个章节更多的是概念,没有太多代码实例,所以希望读者谅解,有什么笔误来Email告知:silentbalanceyh@https://www.doczj.com/doc/9b14415347.html,,本文尽量涵盖所有Java语言可以碰到的和内存相关的内容,同样也会提到一些和内存相关的计算机语言的一些知识,为草案。因为平时开发的时候没有特殊情况不会进行内存管理,所以有可能有笔误的地方比较多,我用的是Windows平台,所以本文涉及到的与操作系统相关的只是仅仅局限于Windows平台。不仅仅如此,这一个章节牵涉到的多线程和另外一些内容并没有讲到,这里主要是结合JVM内部特性把本章节作为核心的概念性章节来讲解,这样方便初学者深入以及彻底理解Java 语言) 本文章节: 1.JMM简介 2.堆和栈 3.本机内存 4.防止内存泄漏 1.JMM简介 i.内存模型概述 Java平台自动集成了线程以及多处理器技术,这种集成程度比Java以前诞生的计算机语言要厉害很多,该语言针对多种异构平台的平台独立性而使用的多线程技术支持也是具有开拓性的一面,有时候在开发Java同步和线程安全要求很严格的程序时,往往容易混淆的一个概念就是内存模型。究竟什么是内存模型?内存模型描述了程序中各个变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量这样的底层细节,对象最终是存储在内存里面的,这点没有错,但是编译器、运行库、处理器或者系统缓存可以有特权在变量指定内存位置存储或者取出变量的值。【JMM】(Java Memory Model的缩写)允许编译器和缓存以数据在处理器特定的缓存(或寄存器)和主存之间移动的次序拥有重要的特权,除非程序员使用了final或synchronized明确请求了某些可见性的保证。 1)JSR133:

Java内存泄露模拟及分析解决方法

derwee Java内存泄露模拟及分析解决方法 1.1 实践目标: 1、使用JA V A代码实现模拟内存溢出 2、分析JDK内存溢出的原因 3、总结存在bug的JA V A编码实践 4、总结JVM优化的方法 1.2 模拟内存溢出: 为了方便模拟内存,特意把JVM的内存参数指定为更小(我的本本内存是8G的)。修改eclipse参数文件调用JVM参数: -vmargs -Xms40m(原始是-Xms40m) -Xmx100m(原始是-Xmx384m) 演示JA V A小程序实现原理:使用集合类对象装载大量的Persion对象,每次把new出来的对象加入集合类对象后,更改对象的属性,再从集合类对象中删除该对象。会出现该删除的对象没有被删掉,Persion类对象不断占用内存,导致分配给JVM的内存被耗光。 package .*; /** * * @ClassName: OutOfMemory * @Description: 内存溢出模拟,提出解决方法 * @author yangdw * @date 2012-3-25 下午6:58:49 */ public class OutOfMemory { public static void main(String[] args) { Collection collection = new HashSet(); for(int i=0;i<0;i++) { Persion per = new Persion(i,"yangdw"); (per);

1.2.1equals和hashcode重写原则[2] 1.2.1.1 对equals()应该遵循如下要求 1)对称性:如果(y)返回是“true”,那么(x)也应该返回是“true”。 2)自反性:(x)必须返回是“true”。 3)传递性:如果(y)返回是“true”,而且(z)返回是“true”,那么(x)也应该 返回是“true”。 4)任何情况下,(null),永远返回是“false”。 5)(和x不同类型的对象)永远返回是“false”。 1.2.1.2 hashCode()的返回值和equals()的关系如下 1)如果(y)返回“true”,那么x和y的hashCode()必须相等。 2)如果(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不 等。

JAVA_内存管理总结

JAVA内存管理总结 1.java是如何管理内存的 Java的内存管理就是对象的分配和释放问题。(两部分) 分配:内存的分配是由程序完成的,程序员需要通过关键字new为每个对象申请内存空间(基本类型除外),所有的对象都在堆(Heap)中分配空间。 释放:对象的释放是由垃圾回收机制决定和执行的,这样做确实简化了程序员的工作。但同时,它也加重了JVM的工作。因为,GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。 2.什么叫java的内存泄露 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连(也就是说仍存在该内存对象的引用);其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。 3.JVM的内存区域组成 java把内存分两种:一种是栈内存,另一种是堆内存1。在函数中定义的基本类型变量和对象的引用变量都在函数的栈内存中分配;2。堆内存用来存放由new创建的对象和数组以及对象的实例变量在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间;在堆中分配的内存由java虚拟机的自动垃圾回收器来管理 堆和栈的优缺点 堆的优势是可以动态分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的。 缺点就是要在运行时动态分配内存,存取速度较慢;栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。 另外,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。 4.Java中数据在内存中是如何存储的 a)基本数据类型

JVM内存最大能调多大分析

JVM内存最大能调多大分析【经典】 2010-11-10 13:21 转载自 最终编辑 上次用weblogic 把 -XmxXXXX 设成2G,就启动不起来,设小点就起来了,当时很气,怎么2G都起不了,今天在看到了一篇解释,转过来了 这次一位老友提出了这个问题,记得当年一个java高手在blogjava提出后,被骂得半死。大家使用java -XmxXXXX -version版本得出了不同的结论。后来老友说大概是1800M左右,我当时反驳,“我设置过服务器8G内存,我使用两个tomcat,每个2G”。为此,我翻开所有的JVM的内存管理的c代码,没有任何结论。我不是linux内核程序员,但是我看过linux的源码,知道32位体系结构的计算机寻址空间是2^32=4G,intel Pentium Pro处理器寻址空间是36位,CPU内部增加了PAE寄存器。用于处理多出来的4根地址 线的使用,所以PAE的技术实现最大2^36=64G寻址。通过linux的内核源码,标准Linux内核对于物理内存的管理采用1:3的分配比例,即物理内存的1/4为内核空间(kernel space),剩下的3/4为用户进程空间(user space),因此,在一台4G内存的服务器上,用户进程可使用的内存最大也就是3G。当进程被内核调入CPU运行时,不同的地址空间数据会被调入4G以内的用户进程空间,其实就能用3G。 IA32架构上,单一进程是不能使用超过4G的内存空间的。但是我记得我给mysql server分配内存大约是左右,不是2的32次方-1,我分配java 2G内存的计算机是IBM的RS6000. 经过不同平台的测试,我得出了大概的数值,win2k下左右,nt下,原因是这样的,Classic VM and HotSpot VM 存放用户区的连续地址中,NT把 kernel DLLs 放在 0x7c 开头的地址空间,所以nt下只有<2G的空间,所以JVM heap 使用极限是2G.用户的dll开始于0x,用户的应用程序开始于0x00400000.我现在唯一确定的是sun可能为了防止和某些 JVM插件的冲突,把dll的地址给rebase一下,这样使用的空间就很少了一部分.为什末rebase,原因是这样的,因为在windows下编译 dll 的默认地址都是, 一般在release之前的时候要rebase一下,rebase 的-b 这个参数是指定一个起始地址,MSDN建议地址是0x,这个工具随visual studio和platform SDK发放。 例如 -b 0x6D000000 \jdk\jre\bin\*.dll \jdk\jre\bin\hotspot\这样你的JVM用的内存多一些,目前关于这个我只能得到BEA的 JRockit最大也只能使用内存,看来各家编译JDK时都作了些手脚. 目前只能得到bea的的-Xmx最小值是16 MB,sun的资料很不全,还好java开源了,可以不依靠sun了. sun提供的资料 Maximum Address Space Per Process Operating System Maximum Address Space Per Process

高性能JAVA代码之内存管理

高性能JA V A代码之_内存管理 更甚者你写的代码,GC根本就回收不了,直接系统挂掉。GC是一段程序,不是智能,他只回收他认为的垃圾,而不是回收你认为的垃圾。 1、GC垃圾回收: Grabage Collection相信学过JA V A的人都知道这个是什么意思.但是他是如何工作的呢? 首先,JVM在管理内存的时候对于变量的管理总是分新对象和老对象。新对象也就是开发者new出来的对象,但是由于生命周期短,那么他占用的内存并不是马上释放,而是被标记为老对象,这个时候该对象还是要存在一段时间。然后由JVM决定他是否是垃圾对象,并进行回收。 所以我们可以知道,垃圾内存并不是用完了马上就被释放,所以就会产生内存释放不及时的现象,从而降低了内存的使用。而当程序浩大的时候。这种现象更为明显,并且GC的工作也是需要消耗资源的。所以,也就会产生内存浪费。 JVM中的对象生命周期里谈内存回收: 对象的生命周期一般分为7个阶段:创建阶段,应用阶段,不可视阶段,不可到达阶段,可收集阶段,终结阶段,释放阶段。 创建阶段:首先大家看一下,如下两段代码: test1: for( int i=0; i<10000; i++) Object obj=new Object(); test2: Object obj=null; for( int i=0; i<10000; i++) obj=new Object(); 这两段代码都是相同的功能,但是显然test2的性能要比test1性能要好,内存使用率要高,这是为什么呢?原因很简单,test1每次执行for循环都要创建一个Object的临时对象,但是这些临时对象由于JVM的GC不能马上销毁,所以他们还要存在很长时间,而test2则只是在内存中保存一份对象的引用,而不必创建大量新临时变量,从而降低了内存的使用。 另外不要对同一个对象初始化多次。例如: public class A{ private Hashtable table = new Hashtable(); public A(){ table = new Hashtable(); // 这里应该去掉,因为table已经被初始化. } } 这样就new了两个Hashtable,但是却只使用了一个。另外一个则没有被引用.而被忽略掉.浪费了内存.并且由于进行了两次new操作.也影响了代码的执行速度。

java内存泄露、溢出检查方法和工具

JAVA内存泄露、溢出的检查方法、工具介绍 问题发现: 在我们运行的一个项目上线运营后发现运行两天左右就会报内存溢出,只有重启tomcat才能恢复服务,异常信息如下: https://www.doczj.com/doc/9b14415347.html,ng.OutOfMemoryError: GC overhead limit exceeded https://www.doczj.com/doc/9b14415347.html,ng.OutOfMemoryError: Java heap space 原因分析: 在此之前必须先介绍一下关于jvm的内存控制,JVM即java虚拟机,它运行时候占用一定的内存,其大小是有限定的,如果程序在运行时jvm占用的内存大于某个限度,则会产生内存溢出,也就是“https://www.doczj.com/doc/9b14415347.html,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的垃圾回归所回收,导致不断占用原分配的内存而不释放,导致不断申请更多的内存直到超过内存设置而导致内存溢出。

相关主题
文本预览
相关文档 最新文档