国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務(wù)器之家 - 編程語(yǔ)言 - JAVA教程 - 淺談Java的虛擬機(jī)結(jié)構(gòu)以及虛擬機(jī)內(nèi)存的優(yōu)化

淺談Java的虛擬機(jī)結(jié)構(gòu)以及虛擬機(jī)內(nèi)存的優(yōu)化

2020-04-09 14:55goldensun JAVA教程

這篇文章主要介紹了Java的虛擬機(jī)結(jié)構(gòu)以及虛擬機(jī)內(nèi)存的優(yōu)化,講到了JVM的堆和棧空間及GC垃圾回收等重要知識(shí),需要的朋友可以參考下

工作以來(lái),代碼越寫(xiě)越多,程序也越來(lái)越臃腫,效率越來(lái)越低,對(duì)于我這樣一個(gè)追求完美的程序員來(lái)說(shuō),這是絕對(duì)不被允許的,于是除了不斷優(yōu)化程序結(jié)構(gòu)外,內(nèi)存優(yōu)化和性能調(diào)優(yōu)就成了我慣用的“伎倆”。

要對(duì)Java程序進(jìn)行內(nèi)存優(yōu)化和性能調(diào)優(yōu),不了解虛擬機(jī)的內(nèi)部原理(或者叫規(guī)范更嚴(yán)謹(jǐn)一點(diǎn))是肯定不行的,這里推薦一本好書(shū)《深入Java虛擬機(jī)(第二版)》(Bill Venners著,曹曉剛 蔣靖 譯,實(shí)際上本文正是作者閱讀本書(shū)之后,對(duì)Java虛擬機(jī)的個(gè)人理解闡述)。當(dāng)然了,了解Java虛擬機(jī)的好處并不僅限于上述兩點(diǎn)好處。從更深一點(diǎn)的技術(shù)層面上看,了解Java虛擬機(jī)的規(guī)范和實(shí)現(xiàn),將更加有助于我們編寫(xiě)高效、穩(wěn)定的Java代碼。比如,假如了解Java虛擬機(jī)的內(nèi)存模型,了解虛擬機(jī)的內(nèi)存回收機(jī)制,那么我們就不會(huì)過(guò)分依賴(lài)它,而會(huì)在需要的時(shí)候顯式的”釋放內(nèi)存”(Java代碼不能顯式釋放內(nèi)存,但是可以通過(guò)釋放對(duì)象引用告知垃圾回收器回收該對(duì)象需要被回收),以降低不必要的內(nèi)存消耗;假如我們了解Java棧的工作原理,那么我們就可以通過(guò)減少遞歸層數(shù),減少循環(huán)次數(shù)來(lái)降低堆棧溢出的風(fēng)險(xiǎn)。可能對(duì)于應(yīng)用開(kāi)發(fā)人員來(lái)說(shuō),可能不會(huì)直接去涉及這些Java虛擬機(jī)底層實(shí)現(xiàn)的工作,但是了解這些背景知識(shí),或多或少,都會(huì)對(duì)我們寫(xiě)的程序產(chǎn)生潛移默化的好的影響。

本篇文章,將簡(jiǎn)明扼要的說(shuō)明Java虛擬機(jī)的體系結(jié)構(gòu)和內(nèi)存模型,如有用詞不妥或解釋不準(zhǔn)確之處,請(qǐng)不吝指正,深感榮幸!

Java 虛擬機(jī)體系結(jié)構(gòu)

淺談Java的虛擬機(jī)結(jié)構(gòu)以及虛擬機(jī)內(nèi)存的優(yōu)化

類(lèi)裝載子系統(tǒng)

Java虛擬機(jī)有兩種類(lèi)裝載器,分別是啟動(dòng)類(lèi)裝載器和用戶(hù)自定義裝載器。

通類(lèi)裝載子系統(tǒng)通過(guò)類(lèi)的全限定名(包名和類(lèi)名,網(wǎng)絡(luò)裝載還包括 URL)將 Class 裝載進(jìn)運(yùn)行時(shí)數(shù)據(jù)區(qū)。對(duì)于每一個(gè)被裝載的類(lèi)型,Java虛擬機(jī)都會(huì)創(chuàng)建一個(gè)java.lang.Class類(lèi)的實(shí)例來(lái)代表該類(lèi)型,該實(shí)例被放在內(nèi)存中的堆區(qū),而裝載的類(lèi)型信息則位于方法區(qū),這一點(diǎn)和所有其他對(duì)象都是一樣的。

類(lèi)裝載子系統(tǒng)在裝載一個(gè)類(lèi)型前,除了要定位和導(dǎo)入對(duì)應(yīng)的二進(jìn)制class文件外,還要驗(yàn)證導(dǎo)入類(lèi)的正確性,為類(lèi)變量分配并初始化內(nèi)存,以及解析符號(hào)引用為直接引用,這些動(dòng)作嚴(yán)格按照以下順序進(jìn)行:

1)裝載——查找并裝載類(lèi)型的二進(jìn)制數(shù)據(jù);

2)連接——執(zhí)行驗(yàn)證,準(zhǔn)備以及解析(可選)

3)驗(yàn)證 確保被導(dǎo)入類(lèi)型的正確性

4)準(zhǔn)備 為類(lèi)變量分配內(nèi)存,并將其初始化為默認(rèn)值

5)解析 把類(lèi)型中的符號(hào)引用轉(zhuǎn)換為直接應(yīng)用

方法區(qū)

對(duì)于每一個(gè)被類(lèi)裝載子系統(tǒng)裝載的類(lèi)型,虛擬機(jī)都會(huì)保存下列數(shù)據(jù)到方法區(qū):

1.類(lèi)型的全限定名

2.類(lèi)型超類(lèi)的全限定名(java.lang.Object沒(méi)有超類(lèi))

3.類(lèi)型是類(lèi)類(lèi)型還是接口類(lèi)型

4.類(lèi)型的訪問(wèn)修飾符

5.任何直接超接口的全限定名有序列表

除了上述基本類(lèi)型信息,還將保存如下信息:

6.類(lèi)型的常量池
7.字段信息(包括字段名、字段類(lèi)型、字段修飾符)
8.方法信息(包括方法名、返回類(lèi)型、參數(shù)的數(shù)量和類(lèi)型、方法修飾符,如果方法不是抽象和本地的,還將保存方法的字節(jié)碼、操作數(shù)棧和該方法棧幀中的局部變量區(qū)的大小和異常表)
9.常量以外的所有類(lèi)變量(其實(shí)就是類(lèi)的靜態(tài)變量,因?yàn)殪o態(tài)變量是所有實(shí)例共享的,且與類(lèi)型直接相關(guān),所以他們是類(lèi)一級(jí)的變量,作為類(lèi)的成員被保存在方法區(qū))
10.一個(gè)到類(lèi)ClassLoader的引用

?
1
2
3
4
5
6
//返回的就是剛才保存的ClassLoader引用
String.class.getClassLoader();
一個(gè)到Class類(lèi)的引用
 
//將返回剛才保存的Class類(lèi)的引用
String.class;

注意,方法區(qū)也是可以被垃圾回收器回收的。

Java程序在運(yùn)行時(shí)創(chuàng)建的所有類(lèi)實(shí)例或數(shù)組都放在同一個(gè)堆中,而每一個(gè)Java虛擬機(jī)也是有一個(gè)堆空間,所有線程共享一個(gè)堆(這就是一個(gè)多線程的Java程序會(huì)產(chǎn)生對(duì)象訪問(wèn)的同步問(wèn)題的原因了)。

由于每一種Java虛擬機(jī)都有對(duì)虛擬機(jī)規(guī)范的不同實(shí)現(xiàn),所以我們可能不知道每一種Java虛擬機(jī)在堆中是以何種形式表示對(duì)象實(shí)例的,不過(guò)我們可以通過(guò)下面這可能的實(shí)現(xiàn)來(lái)一窺端倪:

淺談Java的虛擬機(jī)結(jié)構(gòu)以及虛擬機(jī)內(nèi)存的優(yōu)化

程序計(jì)數(shù)器

對(duì)于運(yùn)行中的Java程序而言,每一個(gè)線程都有自己的PC(程序計(jì)數(shù)器)寄存器,它是在該線程啟動(dòng)時(shí)創(chuàng)建的,大小為一個(gè)字長(zhǎng),用來(lái)保存需要被執(zhí)行的下一行代碼的位置。

Java棧

每一個(gè)線程都有一個(gè)Java棧,以棧幀為單位保存線程的運(yùn)行狀態(tài)。虛擬機(jī)對(duì)Java棧的操作有兩種:壓棧和出棧,二者都已幀為單位。棧幀保存了傳入?yún)?shù)、局部變量、中間運(yùn)算結(jié)果等數(shù)據(jù),在方法完成時(shí)被彈出,然后釋放。

看一下兩個(gè)局部變量相加時(shí)棧幀的內(nèi)存快照

淺談Java的虛擬機(jī)結(jié)構(gòu)以及虛擬機(jī)內(nèi)存的優(yōu)化

本地方法棧

這是 Java 調(diào)用操作系統(tǒng)本地庫(kù)的地方,用來(lái)實(shí)現(xiàn) JNI(Java Native Interface,Java 本地接口)

執(zhí)行引擎

Java虛擬機(jī)的核心,控制裝入 Java 字節(jié)碼并解析;對(duì)于運(yùn)行中的Java程序而言,每一個(gè)線程都是一個(gè)獨(dú)立的虛擬機(jī)執(zhí)行引擎的實(shí)例,從線程生命周期的開(kāi)始到結(jié)束,他要么在執(zhí)行字節(jié)碼,要么在執(zhí)行本地方法。

本地接口

連接了本地方法棧和操作系統(tǒng)庫(kù)。

注:文中所有提到”Java虛擬機(jī)”的地方都是指”JavaEE和JavaSE平臺(tái)的Java虛擬機(jī)規(guī)范”。

虛擬機(jī)內(nèi)存優(yōu)化實(shí)踐

既然提到內(nèi)存,就不得不說(shuō)到內(nèi)存泄露。眾所周知,Java是從C++的基礎(chǔ)上發(fā)展而來(lái)的,而C++程序的很大的一個(gè)問(wèn)題就是內(nèi)存泄露難以解決,盡管Java的JVM有一套自己的垃圾回收機(jī)制來(lái)回收內(nèi)存,在許多情況下并不需要java程序開(kāi)發(fā)人員操太多的心,但也是存在泄露問(wèn)題的,只是比C++小一點(diǎn)。比如說(shuō),程序中存在被引用但無(wú)用的對(duì)象:程序引用了該對(duì)象,但后續(xù)不會(huì)或者不能再使用它,那么它占用的內(nèi)存空間就浪費(fèi)了。

我們先來(lái)看看GC是如何工作的:監(jiān)控每一個(gè)對(duì)象的運(yùn)行狀態(tài),包括對(duì)象的申請(qǐng)、引用、被引用、賦值等,當(dāng)該對(duì)象不再被引用時(shí),釋放對(duì)象(GC本文的重點(diǎn),不做過(guò)多闡述)。很多Java程序員過(guò)分依賴(lài)GC,但問(wèn)題的關(guān)鍵是無(wú)論JVM的垃圾回收機(jī)制做得多好,內(nèi)存總歸是有限的資源,因此就算GC會(huì)為我們完成了大部分的垃圾回收,但適當(dāng)?shù)刈⒁饩幋a過(guò)程中的內(nèi)存優(yōu)化還是很必要的。這樣可以有效的減少GC次數(shù),同時(shí)提升內(nèi)存利用率,最大限度地提高程序的效率。

總體而言,Java虛擬機(jī)的內(nèi)存優(yōu)化應(yīng)從兩方面著手:Java虛擬機(jī)和Java應(yīng)用程序。前者指根據(jù)應(yīng)用程序的設(shè)計(jì)通過(guò)虛擬機(jī)參數(shù)控制虛擬機(jī)邏輯內(nèi)存分區(qū)的大小以使虛擬機(jī)的內(nèi)存與程序?qū)?nèi)存的需求相得益彰;后者指優(yōu)化程序算法,降低GC負(fù)擔(dān),提高GC回收成功率。

通過(guò)參數(shù)優(yōu)化虛擬機(jī)內(nèi)存的參數(shù)如下所示:

Xms

初始Heap大小

Xmx

java heap最大值

Xmn

young generation的heap大小

Xss

每個(gè)線程的Stack大小

上面是三個(gè)比較常用的參數(shù),還有一些:

XX:MinHeapFreeRatio=40

Minimum percentage of heap free after GC to avoid expansion.

XX:MaxHeapFreeRatio=70

Maximum percentage of heap free after GC to avoid shrinking.

XX:NewRatio=2

Ratio of new/old generation sizes. [Sparc -client:8; x86 -server:8; x86 -client:12.]-client:8 (1.3.1+), x86:12]

XX:NewSize=2.125m

Default size of new generation (in bytes) [5.0 and newer: 64 bit VMs are scaled 30% larger; x86:1m; x86, 5.0 and older: 640k]

XX:MaxNewSize=

Maximum size of new generation (in bytes). Since 1.4, MaxNewSize is computed as a function of NewRatio.

XX:SurvivorRatio=25

Ratio of eden/survivor space size [Solaris amd64: 6; Sparc in 1.3.1: 25; other Solaris platforms in 5.0 and earlier: 32]

XX:PermSize=

Initial size of permanent generation

XX:MaxPermSize=64m

Size of the Permanent Generation. [5.0 and newer: 64 bit VMs are scaled 30% larger; 1.4 amd64: 96m; 1.3.1 -client: 32m.]

下面所說(shuō)通過(guò)優(yōu)化程序算法來(lái)提高內(nèi)存利用率,并降低內(nèi)存風(fēng)險(xiǎn),完全是經(jīng)驗(yàn)之談,僅供參考,如有不妥,請(qǐng)指正,謝謝!

1.盡早釋放無(wú)用對(duì)象的引用(XX = null;)

看一段代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public List<PageData> parse(HtmlPage page) {
  List<PageData> list = null;  
  try {
   List valueList = page.getByXPath(config.getContentXpath());
   if (valueList == null || valueList.isEmpty()) {
    return list;
   }
   //需要時(shí)才創(chuàng)建對(duì)象,節(jié)省內(nèi)存,提高效率
   list = new ArrayList<PageData>();
   PageData pageData = new PageData();
   StringBuilder value = new StringBuilder();
   for (int i = 0; i < valueList.size(); i++) {
    HtmlElement content = (HtmlElement) valueList.get(i);
    DomNodeList<HtmlElement> imgs = content.getElementsByTagName("img");
    if (imgs != null && !imgs.isEmpty()) {
     for (HtmlElement img : imgs) {
      try {
       HtmlImage image = (HtmlImage) img;
       String path = image.getSrcAttribute();
       String format = path.substring(path.lastIndexOf("."), path.length());
       String localPath = "D:/images/" + MD5Helper.md5(path).replace("\\", ",").replace("/", ",") + format;
       File localFile = new File(localPath);
       if (!localFile.exists()) {
        localFile.createNewFile();
        image.saveAs(localFile);
       }
       image.setAttribute("src", "file:///" + localPath);
       localFile = null;
       image = null;
       img = null;
      } catch (Exception e) {
      }
     }
     //這個(gè)對(duì)象以后不會(huì)在使用了,清除對(duì)其的引用,等同于提前告知GC,該對(duì)象可以回收了
     imgs = null;
    }
    String text = content.asXml();
    value.append(text).append("<br/>");
    valueList=null;
    content = null;
    text = null;
   }
   pageData.setContent(value.toString());
   pageData.setCharset(page.getPageEncoding());   
   list.add(pageData);
   //這里 pageData=null; 是沒(méi)用的,因?yàn)閘ist仍然持有該對(duì)象的引用,GC不會(huì)回收它
   value=null;
   //這里可不能 list=null; 因?yàn)閘ist是方法的返回值,否則你從該方法中得到的返回值永遠(yuǎn)為空,而且這種錯(cuò)誤不易被發(fā)現(xiàn)、排除
  } catch (Exception e) {   
  }  
  return list;
}

2.謹(jǐn)慎使用集合數(shù)據(jù)類(lèi)型,如數(shù)組,樹(shù),圖,鏈表等數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)對(duì)GC來(lái)說(shuō)回收更復(fù)雜。

3.避免顯式申請(qǐng)數(shù)組空間,不得不顯式申請(qǐng)時(shí),盡量準(zhǔn)確估計(jì)其合理值。

4.盡量避免在類(lèi)的默認(rèn)構(gòu)造器中創(chuàng)建、初始化大量的對(duì)象,防止在調(diào)用其自類(lèi)的構(gòu)造器時(shí)造成不必要的內(nèi)存資源浪費(fèi)

5.盡量避免強(qiáng)制系統(tǒng)做垃圾內(nèi)存的回收,增長(zhǎng)系統(tǒng)做垃圾回收的最終時(shí)間

6.盡量做遠(yuǎn)程方法調(diào)用類(lèi)應(yīng)用開(kāi)發(fā)時(shí)使用瞬間值變量,除非遠(yuǎn)程調(diào)用端需要獲取該瞬間值變量的值。

7.盡量在合適的場(chǎng)景下使用對(duì)象池技術(shù)以提高系統(tǒng)性能

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日韩欧美一区二区中文字幕 | 亚洲精品乱码久久久久久久 | 久久综合久久久 | 久久精品国产精品青草 | 免费av在线播放 | 久久社区 | 亚洲高清电影 | 国产精品久久久久久久久久久久久 | 免费看一区二区三区 | 香蕉久久一区二区不卡无毒影院 | 欧美日本一区二区三区 | 欧美日韩一区二区在线 | 成人午夜在线播放 | 亚洲国产视频一区 | 日本a v网站| 中国一级毛片 | 国产精品一码二码三码在线 | 欧美日韩综合视频 | 精品国产乱码久久久久久丨区2区 | 亚洲欧洲精品成人久久奇米网 | 欧美精品1区2区 | 亚洲精品一区二区三区四区高清 | 五月激情综合网 | 久久1区| av大片 | 黄色网页免费看 | 国产精品久久久久国产a级 国产免费久久 | 久久精品国产77777蜜臀 | 精品视频网站 | 国产精品美女久久久 | 午夜黄色 | a级性生活 | 欧美成人精品一区二区男人看 | 久久丁香 | 国产精品久久久久久中文字 | 国产欧美在线观看 | 日韩av在线免费 | 成人刺激视频在线 | 春色网站 | а天堂中文最新一区二区三区 | 精品久|