瞬间值
相信你在做远程方法调用(RMI)类的应用开发时,应该遇到过使用瞬间值(transient)变量与实现java.lang.Serializable接口的问题,之所以要使对象实现java.lang.Serializable接口,是因为这样就可以从远程环境以对象流的方式,将对象传递到相应的调用环境中,但是有时这些被传递的对象的一些属性数据并不需要被传递,因为这些数据成员对于应用需求而言是无关紧要的,那么这些数据变量就可以将其声明为瞬间值变量。被声明成瞬间值的变量就不会被传递,这样就可以节约调用端运行环境的内存资源,尤其是这个瞬间值变量所携带的数据量越大时(例如,数据量较大的数组),其效用就越大。但是如果该属性在类中是相对重要的,并且调用方需要得到确切的值,此时,你是不能将其声明为瞬间值属性的,否则调用方将无法得到这个属性值。
因此采用瞬间值的方法确实可以节约在远程方法调用(RMI)应用中调用方的内存资源并且可以节约不必要的网络开销,加快传输速度,提高系统性能,但是采用瞬间值的方法时要尽量慎重,避免因误用而导致应用无法正常工作,而达不到预期的效果
我们前面所提到的堆内存(heap)是由Java虚拟机控制管理的,因此,这些参数对JVM而言都有一个默认值,但在某些情况下这些参数的默认值并不是最优的,这就需要我们通过调整这些参数的值来提高JVM的性能,最终提高应用的性能指标。
在实际的应用开发中,如果应用所使用的系统内存较大,经常会引发内存溢出的错误:
…
java.lang.OutOfMemoryError <<no stack trace available>>
java.lang.OutOfMemoryError <<no stack trace available>>
Exception in thread "main"
…
这可能是因为应用要使用的堆内存(heap)超过了JVM所管理内存范围,如果我们适当追加内存值有时就可以避免这种致命错误的出现。
在WINDOWS系统上你可以通过参数-verbosegc查看JVM回收内存的信息,在HP UNIX系统上你可以通过-Xverbosegc:file=/tmp/gc$$.out参数将信息重定向到一个文件中。然后查看相应的信息,例如下面的这个类。
public class A {
public static void main(String args[]) {
for (int i =0 ;i < 100000;++i) {
A a = new A();
}
System.out.println("this is a GC test");
}
}
在类A的main方法中创建了100 000个A对象,然后我们看一下JVM回收内存的情况,编译并执行这个类:
>java -verbosegc A
[GC 512K->91K(1984K), 0.0027537 secs]
this is a GC test
从输出信息中可以看出总共有1984KB的内存被回收,耗时0.002 753 7秒。现在我们将类A添加一行清除对象引用的代码:
public class A {
public static void main(String args[]) {
for (int i =0 ;i < 100000;++i) {
A a = new A();
a = null;
}
System.out.println("this is a GC test");
}
}
编译并执行这个类:
>java -verbosegc A
[GC 512K->91K(1 984K), 0.0 027 450 secs]
this is a GC test
我们看到被回收内存的数量并没有变化,但是回收所需要的时间却变成了0.002 745 0秒,后者比前者节省了0.000 008 7秒,千万不要小看这0.000 008 7秒,当你的应用足够复杂时这个时间就会成指数级增长,看来我们主动清除对象引用的方法,确实可以加速JVM对垃圾内存的回收。
如果再在类A中加入一行强制系统内存回收的代码,结果又会怎样呢?如下所示:
public class A {
public static void main(String args[]) {
for (int i =0 ;i < 100000;++i) {
A a = new A();
a = null;
}
System.gc();
System.out.println("this is a GC test");
}
}
编译并执行这个类:
>java -verbosegc A
[GC 512K->91K(1984K), 0.0 027 272 secs]
[Full GC 487K->91K(1984K), 0.0 070 730 secs]
this is a GC test
系统这次做了两次内存回收,第一次是程序中强制系统内存回收的代码System.gc()导致的内存回收,而后者是系统最终的内存回收操作,我们看到强制内存回收耗时不长,可是却导致了系统最终垃圾回收的时间加长了很多,因此我们在采用强制系统垃圾回收(通过显式调用方法System.gc())的办法来回收系统垃圾内存的办法,还是存在一些弊端的,应尽量少用,或者说只在必要的时候应用。
上面我们提到的内存回收操作就是回收JVM所管理的堆内存(heap)。当系统连续申请内存并且超过JVM所管理的堆内存(heap)的最大值时,就会产生系统内存溢出的致命异常,下面我们来看一下怎样通过设置JVM的内存参数来优化JVM对内存的管理,避免内存溢出异常的发生
由Java源文件.java文件编译成JVM 可解释执行的Java字节文件.class。因所采用的编译方式的不同而大小也不同。通常.class文件的大小也存在是否占用较大内存的问题。通过降低.class文件的大小,不但可以降低系统内存的开销,还可以节省网络开销,虽然这部分内容与JVM内存管理联系不大,但是我觉得还是有必要提一下,因为这在你开发Applet应用时会有帮助(注:在本书后续的章节中,将会对如何减小Java类尺寸的技术话题做更为深入的探讨)。因为一般来说,Applet应用都是靠网络分布式传输由客户端浏览器装载运行的,如果类文件较大,无疑将会增大网络开销,降低传输速度无法满足用户的需求,并且如果类文件较大,无疑也会消耗客户端内存资源。我们可以通过在Java编译器javac中添加相应的参数,来缩小类文件的大小,解决上面的问题。
通常有三种编译方式会影响类文件的大小。
(1)默认编译方式: javac A.java。
(2)调试编译方式: javac –g A.java。
(3)代码编译方式: javac –g:none A.java。
例如如下所示的简单的类A:
public class A {
public static void main(String args[]) {
for (int i =0 ;i < 100000;++i) {
A a = new A();
}
}
}
通过上面这三种方式编译后的类文件的大小分别为:
默认编译方式:291字节。
调试编译方式:422字节。
代码编译方式:207字节。
采用三种不同的方式,编译产生的类文件的大小差异非常大,这是什么原因导致的呢?原来在于.class文件中包含多个不同的部分或属性。
代码(Code)属性包含实际的方法字节码。源文件信息(SourceFile Information)包含用于生成.class的源文件名称。代码行序号表(LineNumberTable)用来映射源文件中的代码行序号与字节码文件中的序号偏移。本地变量表(LocalVariableTable)用来映射本地变量与栈桢的偏移。
正是由于上面这三种编译方式生成的类文件所包含的信息不同,才导致了类文件的大小差异较大,其包含的信息分别如下所示。
默认编译方式:代码(Code)、源文件信息(SourceFile Information)、代码行序号表(LineNumberTable)。
调试编译方式:代码(Code)、源文件信息(SourceFile Information)、代码行序号表(LineNumberTable)、本地变量表(LocalVariableTable)。
代码编译方式:代码(Code)。
这就是三种编译方式产生类文件大小不同的根本原因。而这三种编译方式在程序开发的不同阶段却都起着非常重要的作用,例如,调试编译方式在程序的调试开发过程中应采用,以获取更为详细的调试信息。因此具体应用上面的三种编译方式中的哪一种,应该适时而定。
分享到:
相关推荐
内存溢出(Out Of Memory,OOM)是Java应用程序中常见的问题,它通常发生在程序请求的内存超过了JVM(Java虚拟机)分配的内存空间。 在Java世界中,JVM负责管理应用程序的内存,包括为对象分配和回收内存。当程序...
服务器配置调整包括内存调优、线程池设置、JVM参数优化等,以确保服务器资源的高效利用。 在应对大促场景时,性能优化尤为重要。可以采用水平扩展,增加服务器数量,通过负载均衡技术分散请求。另外,缓存技术如...
7. **增加JVM内存分配**:如果以上优化措施仍无法解决问题,可以考虑暂时增大JVM的内存分配,但这不是长期解决方案,因为可能会增加对硬件资源的需求。 通过以上方法,我们可以有效地解决Java环境下的内存溢出问题...
Java垃圾收集(GC)是Java编程中至关重要的一个部分,它自动管理程序的内存,以避免内存泄漏和系统...以上内容概述了Java GC的基本概念、内存管理、垃圾回收机制以及优化策略,是深入理解和优化Java程序性能的关键。
通过其可视化界面,我们可以观察到应用的内存使用、线程状态、JVM参数、CPU使用率和垃圾回收详情。这对于JVM的性能优化非常有帮助。特别是在处理内存问题时,VisualVM能够有效地协助检测内存泄漏和解决内存溢出问题...
-T 是显示时间戳再对比 Java 日志停止时间,看来这里才是问题的根源,所以接下来从优化 Java 内存占用、加内存入手尝试解决问题吧! 备注:dmesg 命令是用来在 Unix-like 系统中显示内核的相关信息的。dmesg 全称是...
在MATLAB环境中,有时我们需要对MATLAB的Java虚拟机(JVM)进行性能分析和内存管理优化,这时就可以借助第三方工具如JProfiler。本文将详细讲解如何使用JProfiler 5.2.1来分析MATLAB启动JVM的过程,并提供相关的...
10. **JVM调优**:通过调整JVM参数(如-Xms, -Xmx, -XX:NewRatio等),可以定制Java应用的内存分配策略,以适应不同的运行环境和应用需求。 理解并掌握这些Java内存管理的知识点,对于编写高效、稳定的代码至关重要...
对于后者,可以将"xrebel.jar"添加到项目的类路径中,或者在启动命令行中加入-Xbootclasspath/a参数指向xrebel.jar。 3. 启动调试:在Windows环境下,我们可以使用"startxrebel.bat"脚本来启动XRebel服务。这个...
它以其极低的JVM内存占用、快速的连接速度和优秀的性能而著名。HikariCP的核心设计目标是消除传统连接池的常见性能瓶颈,如线程安全问题、死锁、空闲连接超时等问题。在SpringBoot项目中,可以通过配置`application....
如调整JVM参数,优化SQL查询,使用更高效的算法等。 以上只是构建秒杀系统中的一部分核心知识点,实际项目中还需要考虑更多的细节,如安全性、用户体验、故障恢复机制等。通过合理的架构设计和技术选型,可以确保...