java内存管理,GC,内存泄漏

来源:互联网 发布:java常用算法手册豆瓣 编辑:程序博客网 时间:2024/06/03 00:30
java分了5片内存。
1:寄存器。2:栈。3:堆。4:方法区。:5本地方法区。3:方法区。4:栈。5:堆。
* 寄存器
     -- 在CPU内部,开发人员不能通过代码来控制寄存器的分配,由编译器来管理
* 栈
     -- 在Windows下, 栈是向低地址扩展的数据结构,是一块连续的内存的区域,即栈顶的地址和栈的最大容量是系统预先规定好的。位于通用RAM(随机访问存储器)中。
     -- 优点:由系统自动分配,速度较快。
     -- 缺点:不够灵活,但程序员是无法控制的。创建程序时,JAVA系统必须知道存储在堆栈内所有项的确切生命周期,以便上下移动堆栈指针。
     -- 存放基本数据类型、开发过程中就创建的对象(而不是运行过程中)
* 堆
     -- 是向高地址扩展的数据结构,是不连续的内存区域。位于通用RAM(随机访问存储器)中。
     -- 在堆中,没有堆栈指针,为此也就无法直接从处理器那边获得支持
     -- 堆的好处是有很大的灵活性。如Java编译器不需要知道从堆里需要分配多少存储区域,也不必知道存储的数据在堆里会存活多长时间。
     --缺点是用堆进行存储分配和清理要比用堆栈更耗时。
* 静态存储区域与常量存储区域
     -- 静态存储区用来存放static类型的变量
     -- 常量存储区用来存放常量类型(final)类型的值,一般在只读存储器
* 非RAM存储:如果数据完全存活于程序之外,那么它可以不受任何程序的影响。比如流对象和持久化对象。
     -- 如流对象,是要发送到另外一台机器上的
     -- 持久化的对象,存放在磁盘上
1、声明基本数类型是存放在栈中
2、 另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。 
4、String类型:
String str = new String("abc"); 第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 
String str = "abc"; 而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。 
对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

String,StringBuffer,StringBuild的区别
String:是对象不是原始类型.
           为不可变对象,一旦被创建,就不能修改它的值.任何对String的改变都会引发新的String对象的生成;
           对于已经存在的String对象的修改都是重新创建一个新的对象,然后把新的值保存进去.
           String 是final类,即不能被继承.
StringBuffer:
           是一个可变对象,当对他进行修改的时候不会像String那样重新建立对象
           它只能通过构造函数来建立, StringBuffer sb = new StringBuffer();
          对象被建立以后,在内存中就会分配内存空间,并初始保存一个null.通过它的append方法向其赋值, sb.append("hello");
          是线程安全的
StringBuilder是可变类,线性不安全的,不支持并发操作,不适合多线程中使用,但其在单线程中的性能比StringBuffer高。
三者在执行速度方面的比较:

StringBuilder > StringBuffer > String 

1.如果要操作少量的数据用 = String 

2.单线程操作字符串缓冲区下操作大量数据 = StringBuilder 

3.多线程操作字符串缓冲区下操作大量数据 = StringBuffer

垃圾处理机制

gc不仅负责垃圾回收,还决定内存分配。

   java内存管理主要是对内存中的对象进行内存的分配和回收,我们都知道当我们创建一个对象时,对象的引用放在栈(Stack)中,对象放在堆(heap)中,gc只回收堆里面的对象。当gc检测到一个堆中的一个对象不在被引用时,就会对这个对象进行回收。

 当我们创建一个对象时,gc就会监视这个对象的地址,大小以及状态。gc有特定的回收算法,通常使用有向图来记录管理堆中的对象,通过这种方式来确定那些对象正在被引用,那些已经不在被引用,当一个对象不在被引用时,gc就有权回收这个对象。当然可以使用System.gc();Runtime.getRuntime().gc();来显示调用gc。但是java规范不保证gc不一定立即回收。

      gc可以使我们在开发时候不用考虑内存回收的事情了,可以防止内存泄漏。

垃圾回收的对象:给对象赋予了null,以后再也没有调用过;给对象赋予了新值,即重新分配了内存空间。

垃圾回收的方法

1、跟踪回收

跟踪回收的方式独立于程序,定期运行来检查垃圾,需要较长时间的中断。

2、标记清除

标记清除的方式需要对程序的对象进行两次扫描,第一次从根(Root)开始扫描,被根引用了的对象标记为不是垃圾,不是垃圾的对象引用的对象同样标记为不是垃圾,以此递归。所有不是垃圾的对象的引用都扫描完了之后。就进行第二次扫描,第一次扫描中没有得到标记的对象就是垃圾了,对此进行回收。

3、复制收集

复制收集的方式只需要对对象进行一次扫描。准备一个「新的空间」,从根开始,对对象进行扫,如果存在对这个对象的引用,就把它复制到「新空间中」。一次扫描结束之后,所有存在于「新空间」的对象就是所有的非垃圾对象。

4、引用计数

引用计数是指,针对每一个对象,保存一个对该对象的引用计数,该对象的引用增加,则相应的引用计数增加。如果对象的引用计数为零,则回收该对象。

优点:实现简单,成本小,中断的时间也较小

缺点:如果对象中存在循环引用,就无法被回收;还有一个缺点就是,引用计数不适合在并行中使用,多个线程同时操作引用计数,会引起数值不一样的问题从而导致内存错误。


内存泄漏的问题:保留下来永远不使用的对象就是内存泄漏
1、对象时可达的,即在有向图中,存在通路与其相连。2、对象时无用的,即程序以后不会再使用这些对象。

(1)、大量临时变量的使用,没有及时将对象设置为null也可能导致内存的泄露

(2)、数据库的连接没有关闭情况,包括连接池方法连接数据库,如果没有关闭ResultSet等也都可能出现内存泄露的问题。

(3)、静态集合类像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,所有的对象Object也不能被释放,因为他们也将一直被Vector等应用着。




引用计数


引用计数是指,针对每一个对象,保存一个对该对象的引用计数,该对象的引用增加,则相应的引用计数增加。如果对象的引用计数为零,则回收该对象。

0 0
原创粉丝点击