Java程序包含了大量的对象,我们需要了解它们是从哪里被访问的,变量存储于何处对程序的性能有显著的影响--尤其是某些需要被频繁访问的变量。
我们写一个Java类,在其内部方法中定义的局部变量或对象是存储在stack(堆栈)中的,且JVM是一种stack-based的,因此访问和操纵stack中的数据时性能最佳。而Java类的instance变量(这个类的field)和static变量是在constant pool(常量池)中存储和得到访问的。constant pool中保存了所有的符号引用(symbolic references),指向所有型别(types)、值域(field),以及每个型别所使用的所有函数(mothods)。访问instance和static变量时,由于它们存放于constant pool中,所以JVM需要使用更多更耗时的操作码(分析程序生成的bytecode可以看出来)来访问它们。
下面给出一段代码示例,对比后说明怎么尽可能地使用stack变量:
package test;
public class StackVars {
private int x; // instance变量
private static int staticX; //static 变量
public void stackAccess(int val) { //访问和操作stack变量j
int j = 0;
for (int i = 0; i < val; i ) {
j = 1;
}
}
public void instanceAccess(int val) {//访问和操作instance变量x
for (int i = 0; i < val; i ) {
x = 1;
}
}
public void staticAccess(int val) {//访问和操作static变量staticX
for (int i = 0; i < val; i ) {
staticX = 1;
}
}
}
经测试,发现运行instanceAccess()和staticAccess()方法的时间大约相同,但却比运行stackAccess()方法慢了2~3倍。因此我们对instanceAccess()、staticAccess()两个方法的代码作以下调整,以得到更快的性能:
public void instanceAccess(int val) {//访问和操作instance变量x
int tempX=x;
for (int i = 0; i < val; i ) {
tempX = 1;
}
x=tempX;
}
public void staticAccess(int val) {//访问和操作static变量staticX
int tempStaticX=staticX;
for (int i = 0; i < val; i ) {
tempStaticX = 1;
}
staticX=tempStaticX;
}
改善之处就是将instance和static变量放到循环之外,而用一个stack变量来完成多次局部运算,最后再将这个stack变量的值传回instance或static变量,从而提高了代码的性能。
分享到:
相关推荐
3. **利用局部变量提高效率**:尽可能地使用局部变量代替全局变量,可以减少对堆内存的依赖,提高程序运行效率。 #### 五、总结 通过本文的介绍,我们了解了Java中堆内存与栈内存的基本概念、特点及其应用场景。...
### 关于Java栈与堆的思考 在Java编程语言中,理解栈(stack)与堆(heap)的概念...总之,深入理解Java中的栈与堆不仅能够帮助我们写出更好的代码,还能提高对Java虚拟机内部机制的认识,从而更好地优化应用程序。
- **局部变量优化**:避免在循环体中创建大量临时对象,尽可能使用局部变量。 - **适当调整JVM参数**:如-Xms和-Xmx设置堆内存大小,-XX:NewRatio调整新生代与老年代的比例,-XX:SurvivorRatio调整Eden区和...
- **本地方法栈(Native Method Stack)**:与虚拟机栈所发挥的作用是非常相似的,其区别只是本地方法栈为虚拟机使用到的Native方法服务。 - **程序计数器(Program Counter Register)**:当前线程所执行的字节码的行号...
其中,堆内存是Java对象的主要存储场所,而栈则用于存储线程中的局部变量和方法调用信息。方法区则保存类的信息,如类名、常量、字段和方法数据。 最小内存自适应机制是为了确保应用程序在启动时能够根据实际需求...
当递归调用过深或方法内部定义了大量的局部变量时,可能会耗尽栈空间,引发栈溢出。示例中的`Stack` 类定义了一个无限递归的`test` 方法,每次调用都会在栈上分配新的空间,最终导致`java.lang.StackOverflowError`...
Java内存分配原理主要涉及到以下几个关键区域:...在实际编程中,应尽可能遵循“尽量短生命周期、尽量小对象”的原则,以充分利用栈内存,减少不必要的堆内存分配,同时配合合理的垃圾回收策略,提高程序的运行效率。
在Java中,对象主要存储在堆(Heap)中,而局部变量、方法调用等则存储在栈(Stack)中。垃圾回收主要针对堆内存中的对象进行管理。 ##### 2.3 对象的可达性分析 垃圾回收器通过可达性分析算法来判断对象是否还被...
程序应该尽可能地处理这些异常,以避免程序崩溃。 #### 九、`HashMap`与`Hashtable`的区别 - **`HashMap`**:`HashMap`是非线程安全的,但在性能上通常优于`Hashtable`。它允许使用`null`作为键或值,这在某些场景...
- **尽可能使用stack变量** 将对象声明为局部变量而非成员变量可以减少内存分配的开销。局部变量通常存储在栈中,释放速度快,不会增加垃圾收集的压力。 - **变量初始化** 初始化变量时应尽可能采用简洁高效的...
**栈内存**主要用于存储程序运行过程中的临时数据,如局部变量、方法调用过程中产生的临时数据等。它的特点是先进后出(LIFO,Last In First Out),这意味着最后进入栈的数据会被最先处理。 - **分配方式**:所有...
- **最小化锁定范围**:尽可能减小锁定的代码范围,以减少锁的竞争。 - **使用锁的粒度**:根据实际情况选择最合适的锁粒度。 - **锁的获取与释放**:确保在适当的位置获取和释放锁,避免死锁。 **线程安全的集合类...
它主要分为堆内存(Heap)、栈内存(Stack)、方法区(Method Area)、本地方法栈(Native Method Stack)和程序计数器(PC Register)。其中,堆内存是所有线程共享的一块区域,主要用于对象实例的存储;栈内存则按...
Java编译器并不强制要求程序员处理运行时异常,但良好的编程实践应该考虑到这些异常,并尽可能地避免它们的发生。 另一方面,一般异常(也称为检查型异常,如`IOException`, `SQLException`等)是程序在编译时就...
- **Java虚拟机栈(Java Virtual Machine Stack)**:用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个线程创建时都会创建一个新的栈,每个方法调用时都会创建一个新的栈帧,方法退出时栈帧也会被销毁。...
- 本地方法栈(Native Method Stack):与虚拟机栈类似,但主要用于存储调用本地方法的信息。 - 程序计数器(Program Counter Register):记录当前线程所执行的字节码指令的位置。 3. **执行引擎(Execution ...
- 尽可能使用容器类(如`std::vector`、`std::array`等),它们内部实现了内存管理,减少了出错的可能性。 - 当内存需求不确定时,考虑使用动态增长的数据结构(如`std::vector`)而非手动调整大小。 总的来说,...
在Java中,内存分为堆内存(Heap)和栈内存(Stack),其中堆内存主要用来存储对象实例,而栈内存用于存储基本类型和对象引用。垃圾回收的主要目标就是找到并清理那些不再被使用的对象,从而释放内存空间,防止内存...
栈(Stack):栈是程序运行时自动分配和释放的内存,主要用于存储函数参数、局部变量等。当函数调用结束,栈上的空间会被自动回收。例如,`funcParamTest` 函数中的 `iFuncParam1`, `iFuncParam2`, `iLocalInt1` 等...