日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java內(nèi)存管理方法小結(jié)

這里向大家簡(jiǎn)單介紹一下Java內(nèi)存管理的概念和方法,Java內(nèi)存管理就是對(duì)象的分配和釋放問題。首先看一下分配和釋放的概念,分配:內(nèi)存的分配是由程序完成的,程序員需要通過關(guān)鍵字new為每個(gè)對(duì)象申請(qǐng)內(nèi)存空間(基本類型除外),所有的對(duì)象都在堆(Heap)中分配空間;而對(duì)象的釋放是由垃圾回收機(jī)制決定和執(zhí)行的。

成都創(chuàng)新互聯(lián)專注于企業(yè)網(wǎng)絡(luò)營銷推廣、網(wǎng)站重做改版、泗水網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5場(chǎng)景定制、成都做商城網(wǎng)站、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為泗水等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

Java內(nèi)存管理總結(jié)

1.Java是如何管理內(nèi)存的

Java內(nèi)存管理就是對(duì)象的分配和釋放問題。
分配:內(nèi)存的分配是由程序完成的,程序員需要通過關(guān)鍵字new為每個(gè)對(duì)象申請(qǐng)內(nèi)存空間(基本類型除外),所有的對(duì)象都在堆(Heap)中分配空間。

釋放:對(duì)象的釋放是由垃圾回收機(jī)制決定和執(zhí)行的,這樣做確實(shí)簡(jiǎn)化了程序員的工作。但同時(shí),它也加重了JVM的工作。這也是Java程序運(yùn)行速度較慢的原因之一。因?yàn)?,GC為了能夠正確釋放對(duì)象,GC必須監(jiān)控每一個(gè)對(duì)象的運(yùn)行狀態(tài),包括對(duì)象的申請(qǐng)、引用、被引用、賦值等,GC都需要進(jìn)行監(jiān)控。

2.什么叫Java的內(nèi)存泄露

在Java內(nèi)存管理中,內(nèi)存泄漏就是存在一些被分配的對(duì)象,這些對(duì)象有下面兩個(gè)特點(diǎn),首先,這些對(duì)象是可達(dá)的,即在有向圖中,存在通路可以與其相連(也就是說仍存在該內(nèi)存對(duì)象的引用);其次,這些對(duì)象是無用的,即程序以后不會(huì)再使用這些對(duì)象。如果對(duì)象滿足這兩個(gè)條件,這些對(duì)象就可以判定為Java中的內(nèi)存泄漏,這些對(duì)象不會(huì)被GC所回收,然而它卻占用內(nèi)存。
與C++內(nèi)存泄露的區(qū)別:

在C++中,內(nèi)存泄漏的范圍更大一些。有些對(duì)象被分配了內(nèi)存空間,然后卻不可達(dá),由于C++中沒有GC,這些內(nèi)存將永遠(yuǎn)收不回來。在Java中,這些不可達(dá)的對(duì)象都由GC負(fù)責(zé)回收,因此程序員不需要考慮這部分的內(nèi)存泄露。

3.JVM的內(nèi)存區(qū)域組成

Java把內(nèi)存分兩種:一種是棧內(nèi)存,另一種是堆內(nèi)存

1。在函數(shù)中定義的基本類型變量和對(duì)象的引用變量都在函數(shù)的棧內(nèi)存中分配;

2。堆內(nèi)存用來存放由new創(chuàng)建的對(duì)象和數(shù)組以及對(duì)象的實(shí)例變量

在函數(shù)(代碼塊)中定義一個(gè)變量時(shí),Java就在棧中為這個(gè)變量分配內(nèi)存空間,當(dāng)超過變量的作用域后,Java會(huì)自動(dòng)釋放掉為該變量所分配的內(nèi)存空間;在堆中分配的內(nèi)存由Java虛擬機(jī)的自動(dòng)垃圾回收器來管理

3。棧的優(yōu)缺點(diǎn)

堆的優(yōu)勢(shì)是可以動(dòng)態(tài)分配內(nèi)存大小,生存期也不必事先告訴編譯器,因?yàn)樗窃谶\(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存的。缺點(diǎn)就是要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,存取速度較慢;

棧的優(yōu)勢(shì)是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。另外,棧數(shù)據(jù)可以共享。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。#p#

4。Java內(nèi)存管理中數(shù)據(jù)如何存儲(chǔ)

a)基本數(shù)據(jù)類型

Java內(nèi)存管理中的基本數(shù)據(jù)類型共有8種,即int,short,long,byte,float,double,boolean,char(注意,并沒有string的基本類型)。這種類型的定義是通過諸如inta=3;longb=255L;的形式來定義的。如inta=3;這里的a是一個(gè)指向int類型的引用,指向3這個(gè)字面值。這些字面值的數(shù)據(jù),由于大小可知,生存期可知(這些字面值定義在某個(gè)程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中。

另外,棧有一個(gè)很重要的特殊性,就是存在棧中的數(shù)據(jù)可以共享。
比如:我們同時(shí)定義:
inta=3;
intb=3;
編譯器先處理inta=3;首先它會(huì)在棧中創(chuàng)建一個(gè)變量為a的引用,然后查找有沒有字面值為3的地址,沒找到,就開辟一個(gè)存放3這個(gè)字面值的地址,然后將a指向3的地址。接著處理intb=3;在創(chuàng)建完b這個(gè)引用變量后,由于在棧中已經(jīng)有3這個(gè)字面值,便將b直接指向3的地址。這樣,就出現(xiàn)了a與b同時(shí)均指向3的情況。

定義完a與b的值后,再令a=4;那么,b不會(huì)等于4,還是等于3。在編譯器內(nèi)部,遇到時(shí),它就會(huì)重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經(jīng)有了,則直接將a指向這個(gè)地址。因此a值的改變不會(huì)影響到b的值。

b)對(duì)象

在Java內(nèi)存管理中,創(chuàng)建一個(gè)對(duì)象包括對(duì)象的聲明和實(shí)例化兩步,下面用一個(gè)例題來說明對(duì)象的內(nèi)存模型。
  假設(shè)有類Rectangle定義如下:

Java代碼

 
 
 
 
  1. classRectangle{
  2.   doublewidth,height;
  3.   Rectangle(doublew,doubleh){
  4.  wwidth=w;
  5. hheight=h;
  6. }
  7. }
  8. classRectangle{
  9.   doublewidth,height;
  10.   Rectangle(doublew,doubleh){
  11.  wwidth=w;
  12. hheight=h;
  13. }
  14. }

      (1)明對(duì)象時(shí)的內(nèi)存模型

  用Rectanglerect;聲明一個(gè)對(duì)象rect時(shí),將在棧內(nèi)存為對(duì)象的引用變量rect分配內(nèi)存空間,但Rectangle的值為空,稱rect是一個(gè)空對(duì)象??諏?duì)象不能使用,因?yàn)樗€沒有引用任何“實(shí)體”。

  (2)對(duì)象實(shí)例化時(shí)的內(nèi)存模型

  當(dāng)執(zhí)行rect=newRectangle(3,5);時(shí),會(huì)做兩件事:
  在堆內(nèi)存中為類的成員變量width,height分配內(nèi)存,并將其初始化為各數(shù)據(jù)類型的默認(rèn)值;接著進(jìn)行顯式初始化(類定義時(shí)的初始化值);最后調(diào)用構(gòu)造方法,為成員變量賦值。
返回堆內(nèi)存中對(duì)象的引用(相當(dāng)于首地址)給引用變量rect,以后就可以通過rect來引用堆內(nèi)存中的對(duì)象了。

c)創(chuàng)建多個(gè)不同的對(duì)象實(shí)例

一個(gè)類通過使用new運(yùn)算符可以創(chuàng)建多個(gè)不同的對(duì)象實(shí)例,這些對(duì)象實(shí)例將在堆中被分配不同的內(nèi)存空間,改變其中一個(gè)對(duì)象的狀態(tài)不會(huì)影響其他對(duì)象的狀態(tài)。例如:

Java代碼

 
 
 
 
  1. Rectangler1=newRectangle(3,5);
  2. Rectangler2=newRectangle(4,6);
  3. Rectangler1=newRectangle(3,5);
  4. Rectangler2=newRectangle(4,6);

  此時(shí),將在堆內(nèi)存中分別為兩個(gè)對(duì)象的成員變量width、height分配內(nèi)存空間,兩個(gè)對(duì)象在堆內(nèi)存中占據(jù)的空間是互不相同的。如果有:

Java代碼

 
 
 
 
  1. Rectangler1=newRectangle(3,5);
  2. Rectangler2=r1;
  3. Rectangler1=newRectangle(3,5);
  4. Rectangler2=r1; 

 則在堆內(nèi)存中只創(chuàng)建了一個(gè)對(duì)象實(shí)例,在棧內(nèi)存中創(chuàng)建了兩個(gè)對(duì)象引用,兩個(gè)對(duì)象引用同時(shí)指向一個(gè)對(duì)象實(shí)例。#p#

d)包裝類

Java內(nèi)存管理中數(shù)據(jù)的基本型別都有對(duì)應(yīng)的包裝類:如int對(duì)應(yīng)Integer類,double對(duì)應(yīng)Double類等,基本類型的定義都是直接在棧中,如果用包裝類來創(chuàng)建對(duì)象,就和普通對(duì)象一樣了。例如:inti=0;i直接存儲(chǔ)在棧中。Integeri(i此時(shí)是對(duì)象)=newInteger(5);這樣,i對(duì)象數(shù)據(jù)存儲(chǔ)在堆中,i的引用存儲(chǔ)在棧中,通過棧中的引用來操作對(duì)象。

e)String

String是一個(gè)特殊的包裝類數(shù)據(jù)??梢杂糜靡韵聝煞N方式創(chuàng)建:

 
 
 
 
  1. 1.Stringstr=newString("abc");
  2. 2.Stringstr="abc";

第一種創(chuàng)建方式,和普通對(duì)象的的創(chuàng)建過程一樣;
第二種創(chuàng)建方式,Java內(nèi)部將此語句轉(zhuǎn)化為以下幾個(gè)步驟:

 (1)先定義一個(gè)名為str的對(duì)String類的對(duì)象引用變量:Stringstr;
 (2)在棧中查找有沒有存放值為“abc”的地址,如果沒有,則開辟一個(gè)存放字面值為“abc”的地址,接著創(chuàng)建一個(gè)新的String類的對(duì)象o,并將o的字符串值指向這個(gè)地址,而且在棧中這個(gè)地址旁邊記下這個(gè)引用的對(duì)象o。如果已經(jīng)有了值為“abc”的地址,則查找對(duì)象o,并返回o的地址。

 (3)將str指向?qū)ο髈的地址。

值得注意的是,一般String類中字符串值都是直接存值的。但像Stringstr="abc";這種場(chǎng)合下,其字符串值卻是保存了一個(gè)指向存在棧中數(shù)據(jù)的引用。
為了更好地說明這個(gè)問題,我們可以通過以下的幾個(gè)代碼進(jìn)行驗(yàn)證。

Java代碼

 
 
 
 
  1. Stringstr1=“abc”;
  2. Stringstr2=“abc”;
  3. System.out.println(s1==s2);//true
  4. Stringstr1=“abc”;
  5. Stringstr2=“abc”;
  6. System.out.println(s1==s2);//true

注意,這里并不用str1.equals(str2);的方式,因?yàn)檫@將比較兩個(gè)字符串的值是否相等。==號(hào),根據(jù)JDK的說明,只有在兩個(gè)引用都指向了同一個(gè)對(duì)象時(shí)才返回真值。而我們?cè)谶@里要看的是,str1與str2是否都指向了同一個(gè)對(duì)象。

  我們?cè)俳又匆韵碌拇a。

Java代碼

 
 
 
 
  1. Stringstr1=newString(“abc”);
  2. Stringstr2=“abc”;
  3. System.out.println(str1==str2);//false
  4. Stringstr1=newString(“abc”);
  5. Stringstr2=“abc”;
  6. System.out.println(str1==str2);//false 

創(chuàng)建了兩個(gè)引用。創(chuàng)建了兩個(gè)對(duì)象。兩個(gè)引用分別指向不同的兩個(gè)對(duì)象。
  以上兩段代碼說明,只要是用new()來新建對(duì)象的,都會(huì)在堆中創(chuàng)建,而且其字符串是單獨(dú)存值的,即使與棧中的數(shù)據(jù)相同,也不會(huì)與棧中的數(shù)據(jù)共享。

f)數(shù)組

當(dāng)定義一個(gè)數(shù)組,intx[];或int[]x;時(shí),在棧內(nèi)存中創(chuàng)建一個(gè)數(shù)組引用,通過該引用(即數(shù)組名)來引用數(shù)組。x=newint[3];將在堆內(nèi)存中分配3個(gè)保存int型數(shù)據(jù)的空間,堆內(nèi)存的首地址放到棧內(nèi)存中,每個(gè)數(shù)組元素被初始化為0。

g)靜態(tài)變量

用static的修飾的變量和方法,實(shí)際上是指定了這些變量和方法在內(nèi)存中的“固定位置”-staticstorage,可以理解為所有實(shí)例對(duì)象共有的內(nèi)存空間。static變量有點(diǎn)類似于C中的全局變量的概念;靜態(tài)表示的是內(nèi)存的共享,就是它的每一個(gè)實(shí)例都指向同一個(gè)內(nèi)存地址。把static拿來,就是告訴JVM它是靜態(tài)的,它的引用(含間接引用)都是指向同一個(gè)位置,在那個(gè)地方,你把它改了,它就不會(huì)變成原樣,你把它清理了,它就不會(huì)回來了。

那靜態(tài)變量與方法是在什么時(shí)候初始化的呢?對(duì)于兩種不同的類屬性,static屬性與instance屬性,初始化的時(shí)機(jī)是不同的。instance屬性在創(chuàng)建實(shí)例的時(shí)候初始化,static屬性在類加載,也就是第一次用到這個(gè)類的時(shí)候初始化,對(duì)于后來的實(shí)例的創(chuàng)建,不再次進(jìn)行初始化。
我們??煽吹筋愃埔韵碌睦觼碚f明這個(gè)問題:

Java代碼

 
 
 
 
  1. classStudent{
  2. staticintnumberOfStudents=0;
  3. Student()
  4. {
  5. numberOfStudents++;
  6. }
  7. }
  8. classStudent{
  9. staticintnumberOfStudents=0;
  10. Student()
  11. {
  12. numberOfStudents++;
  13. }
  14. }

每一次創(chuàng)建一個(gè)新的Student實(shí)例時(shí),成員numberOfStudents都會(huì)不斷的遞增,并且所有的Student實(shí)例都訪問同一個(gè)numberOfStudents變量,實(shí)際上intnumberOfStudents變量在內(nèi)存中只存儲(chǔ)在一個(gè)位置上。


當(dāng)前名稱:Java內(nèi)存管理方法小結(jié)
分享URL:http://www.5511xx.com/article/djoesci.html