Java的初始化机制、垃圾回收机制和内存分配机制
2013-03-18 17:51
681 查看
转:http://blog.csdn.net/vestigge/article/details/8658687
Java的初始化机制、垃圾回收机制和内存分配机制
view plaincopyprint?
public class Parent
{
static Tipout TIP =
new Tipout("父类 static 成员 TIP 初始化");
Tipout tip = new Tipout("父类 成员 tip 初始化");
public Parent()
{
System.out.println("父类 构造函数 调用");
}
}
class Sub extends Parent
{
static Tipout SUB_TIP =
new Tipout("子类 static 成员 SUB_TIP 初始化");
Tipout subTip = new Tipout("子类 成员 subTip 初始化");
public Sub()
{
System.out.println("子类 构造函数 调用");
}
}
class Tipout
{
public Tipout(String s)
{
System.out.println(s);
}
}
执行结果:
父类 static 成员 TIP 初始化
子类 static 成员 SUB_TIP 初始化
父类 成员 tip 初始化
父类 构造函数 调用
子类 成员 subTip 初始化
子类 构造函数 调用
由此可以总结出java初始化的顺序:
->所有静态成员初始化(父类->子类)
-->父类初始化(普通成员->构造函数)
--->子类初始化(普通成员-->构造函数)
!static成员初始化顺序只和类定义中的顺序有关。
调用静态数据和静态方法时,这个类中的所有静态成员都会被初始化(非static成员不会被初始化),前提是他们从未被初始化过。
测试代码:
[java]
view plaincopyprint?
public class Parent
{
public static Tipout TIP =
new Tipout("父类 static 成员 TIP 初始化");
static
{
System.out.println("父类 static 代码块");
}
Tipout tip = new Tipout("父类 成员 tip 初始化");
public Parent()
{
System.out.println("父类 构造函数 调用");
}
public static
void outMsg(){
System.out.println("父类 static 函数 调用");
}
}
在Main()中调用:Parent.TIP.toString();
结果:
一个对象,可以有一个或多个引用变量指向它。当一个对象不再有任何一个引用变量指向它时,这个对象可以被垃圾回收机制回收了。
但是,并不是对象被抛弃后当即被回收的。JVM进程做空间回收有较大的系统开销。如果每当某应用进程丢弃一个对象,就立即回收它的空间,
势必会使整个系统的运转效率非常低下。
!不能操纵垃圾回收
使对象值为null,或者调用System.gc()
JVM接受这个消息后,并不是立即做垃圾回收,而只是对几个垃圾回收算法做了加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。
!垃圾回收器的运行时间是不固定的,清理工作的实际运行时间也是不能预知的。
1.栈内存,
基本类型的变量和对象的引用变量(存取速度比堆要快,仅次于寄存器)
2.堆内存。
堆内存用来存放由 new 创建的对象和数组。
!类跟数组一样,都是属于引用类型,引用类型就是指一堆对内存可以同时被多个栈内存指向。
java中主要存在4块内存空间:
栈内存空间:保存所有的对象名称(更准确地说是保存了引用的堆内存空间的地址)
堆内存空间:保存每个对象的具体属性内容。
全局数据区:保存static类型的属性。
全局代码区:保存所有的方法定义。
2.3.2 String缓冲池
缓冲池是java为了节省内存空间,会在内存中创建一个专门为String设计的缓冲池,用来保存已经存在的字符串,
如果2个字符串是一样的,则使用池中的字符串,不再创建新的对象
用下边的代码测试:
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
结果为true,说明str1和str2指向同一个对象
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new则在堆中创建了2个对象
String str = "hello";
上面这种方式会创建一个"hello"字符串,而且JVM的字符缓存池还会缓存这个字符串。
String str = new String("hello");
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o
2.尽量减少对变量的重复计算
[java]
view plaincopyprint?
for(int i=0;i<list.size();i++)
应该改为
[java]
view plaincopyprint?
for(int i=0,len=list.size();i<len;i++)
并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。
3.避免在循环体中声明创建对象
[java]
view plaincopyprint?
for (int i =
0; i < 10000; i++) {
Object obj = new Object();
}
虽然性能上差别不大,但这样的代码会浪费栈内存空间,上边提到过引用变量会存放在栈内存,这样会在内存中产生大量的对象引用。
应该写成下边的:
[java]
view plaincopyprint?
Object obj;
for (int i =
0; i < 10000; i++) {
obj = new Object();
}
Java的初始化机制、垃圾回收机制和内存分配机制
2.1初始化顺序:
[java]view plaincopyprint?
public class Parent
{
static Tipout TIP =
new Tipout("父类 static 成员 TIP 初始化");
Tipout tip = new Tipout("父类 成员 tip 初始化");
public Parent()
{
System.out.println("父类 构造函数 调用");
}
}
class Sub extends Parent
{
static Tipout SUB_TIP =
new Tipout("子类 static 成员 SUB_TIP 初始化");
Tipout subTip = new Tipout("子类 成员 subTip 初始化");
public Sub()
{
System.out.println("子类 构造函数 调用");
}
}
class Tipout
{
public Tipout(String s)
{
System.out.println(s);
}
}
public class Parent { static Tipout TIP = new Tipout("父类 static 成员 TIP 初始化"); Tipout tip = new Tipout("父类 成员 tip 初始化"); public Parent() { System.out.println("父类 构造函数 调用"); } } class Sub extends Parent { static Tipout SUB_TIP = new Tipout("子类 static 成员 SUB_TIP 初始化"); Tipout subTip = new Tipout("子类 成员 subTip 初始化"); public Sub() { System.out.println("子类 构造函数 调用"); } } class Tipout { public Tipout(String s) { System.out.println(s); } }
执行结果:
父类 static 成员 TIP 初始化
子类 static 成员 SUB_TIP 初始化
父类 成员 tip 初始化
父类 构造函数 调用
子类 成员 subTip 初始化
子类 构造函数 调用
由此可以总结出java初始化的顺序:
->所有静态成员初始化(父类->子类)
-->父类初始化(普通成员->构造函数)
--->子类初始化(普通成员-->构造函数)
!static成员初始化顺序只和类定义中的顺序有关。
调用静态数据和静态方法时,这个类中的所有静态成员都会被初始化(非static成员不会被初始化),前提是他们从未被初始化过。
测试代码:
[java]
view plaincopyprint?
public class Parent
{
public static Tipout TIP =
new Tipout("父类 static 成员 TIP 初始化");
static
{
System.out.println("父类 static 代码块");
}
Tipout tip = new Tipout("父类 成员 tip 初始化");
public Parent()
{
System.out.println("父类 构造函数 调用");
}
public static
void outMsg(){
System.out.println("父类 static 函数 调用");
}
}
public class Parent { public static Tipout TIP = new Tipout("父类 static 成员 TIP 初始化"); static { System.out.println("父类 static 代码块"); } Tipout tip = new Tipout("父类 成员 tip 初始化"); public Parent() { System.out.println("父类 构造函数 调用"); } public static void outMsg(){ System.out.println("父类 static 函数 调用"); } }
在Main()中调用:Parent.TIP.toString();
结果:
2.2垃圾回收
java中并不需要清除对象,也不存在C++中的析构函数,java的垃圾回收机制会自动释放无用的变量。一个对象,可以有一个或多个引用变量指向它。当一个对象不再有任何一个引用变量指向它时,这个对象可以被垃圾回收机制回收了。
但是,并不是对象被抛弃后当即被回收的。JVM进程做空间回收有较大的系统开销。如果每当某应用进程丢弃一个对象,就立即回收它的空间,
势必会使整个系统的运转效率非常低下。
!不能操纵垃圾回收
使对象值为null,或者调用System.gc()
JVM接受这个消息后,并不是立即做垃圾回收,而只是对几个垃圾回收算法做了加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。
!垃圾回收器的运行时间是不固定的,清理工作的实际运行时间也是不能预知的。
2.3内存分配机制
2.3.1Java 把内存划分成两种:1.栈内存,
基本类型的变量和对象的引用变量(存取速度比堆要快,仅次于寄存器)
2.堆内存。
堆内存用来存放由 new 创建的对象和数组。
!类跟数组一样,都是属于引用类型,引用类型就是指一堆对内存可以同时被多个栈内存指向。
java中主要存在4块内存空间:
栈内存空间:保存所有的对象名称(更准确地说是保存了引用的堆内存空间的地址)
堆内存空间:保存每个对象的具体属性内容。
全局数据区:保存static类型的属性。
全局代码区:保存所有的方法定义。
2.3.2 String缓冲池
缓冲池是java为了节省内存空间,会在内存中创建一个专门为String设计的缓冲池,用来保存已经存在的字符串,
如果2个字符串是一样的,则使用池中的字符串,不再创建新的对象
用下边的代码测试:
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
结果为true,说明str1和str2指向同一个对象
String str1 =new String ("abc");
String str2 =new String ("abc");
System.out.println(str1==str2); // false
用new则在堆中创建了2个对象
2.4应该注意的问题:
1.使用以下方式创建字符串String str = "hello";
上面这种方式会创建一个"hello"字符串,而且JVM的字符缓存池还会缓存这个字符串。
String str = new String("hello");
此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o
2.尽量减少对变量的重复计算
[java]
view plaincopyprint?
for(int i=0;i<list.size();i++)
for(int i=0;i<list.size();i++)
应该改为
[java]
view plaincopyprint?
for(int i=0,len=list.size();i<len;i++)
for(int i=0,len=list.size();i<len;i++)
并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。
3.避免在循环体中声明创建对象
[java]
view plaincopyprint?
for (int i =
0; i < 10000; i++) {
Object obj = new Object();
}
for (int i = 0; i < 10000; i++) { Object obj = new Object(); }
虽然性能上差别不大,但这样的代码会浪费栈内存空间,上边提到过引用变量会存放在栈内存,这样会在内存中产生大量的对象引用。
应该写成下边的:
[java]
view plaincopyprint?
Object obj;
for (int i =
0; i < 10000; i++) {
obj = new Object();
}
相关文章推荐
- Java的初始化机制、垃圾回收机制和内存分配机制
- Java的初始化机制、垃圾回收机制和内存分配机制
- 二.Java的初始化机制、垃圾回收机制和内存分配机制
- 二.Java的初始化机制、垃圾回收机制和内存分配机制
- Java的初始化机制、垃圾回收机制和内存分配机制
- Java内存区域分配、存储、垃圾回收策略与回收机制(深入JVM虚拟机)
- JAVA学习第四回:JAVA内存分配与垃圾回收机制:白头而新
- JAVA的内存分配策略和自动垃圾回收机制
- Java内存分配及垃圾回收机制
- Java内存分配及垃圾回收机制
- 【Java面试整理之JVM】深入理解JVM结构、类加载机制、垃圾回收GC原理、JVM内存分配策略、JVM内存泄露和溢出
- Java 内存分配及垃圾回收机制初探
- Java内存分配机制 垃圾回收 GC Root
- (转)Java 内存区域分配和垃圾回收(GC)机制
- 【java虚拟机序列】java中的垃圾回收与内存分配策略
- Java深入 - Java 内存分配和回收机制-转
- Java初始化与垃圾回收机制简单记录
- Java深入——Java 内存分配和回收机制
- Java的初始化机制、垃圾回收机制和内存分配机制
- JAVA 内存管理总结:内存泄露、数据存储、垃圾回收机制一网打尽!