成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

你不得不掌握的JVM內存管理

開發(fā) 后端
Java 引以為豪的就是它的自動內存管理機制。相比于 C++的手動內存管理、復雜難以理解的指針等,Java 程序寫起來就方便的多。

 Java 引以為豪的就是它的自動內存管理機制。相比于 C++的手動內存管理、復雜難以理解的指針等,Java 程序寫起來就方便的多。

然而這種呼之即來揮之即去的內存申請和釋放方式,自然也有它的代價。為了管理這些快速的內存申請釋放操作,就必須引入一個池子來延遲這些內存區(qū)域的回收操作。

我們常說的內存回收,就是針對這個池子的操作。我們把上面說的這個池子,叫作堆,可以暫時把它看成一個整體。

JVM 內存布局

Java 程序的數(shù)據(jù)結構是非常豐富的。其中的內容,舉一些例子:

靜態(tài)成員變

動態(tài)成員變量

區(qū)域變量

短小緊湊的對象聲明

龐大復雜的內存申請

我們先看一下 JVM 的內存布局。隨著 Java 的發(fā)展,內存布局一直在調整之中。比如,Java 8 及之后的版本,徹底移除了持久代,而使用 Metaspace 來進行替代。這也表示著 -XX:PermSize 和 -XX:MaxPermSize 等參數(shù)調優(yōu),已經(jīng)沒有了意義。但大體上,比較重要的內存區(qū)域是固定的。

JVM 內存區(qū)域劃分如圖所示,從圖中我們可以看出:

  •  JVM 堆中的數(shù)據(jù)是共享的,是占用內存最大的一塊區(qū)域。
  •  可以執(zhí)行字節(jié)碼的模塊叫作執(zhí)行引擎。
  •  執(zhí)行引擎在線程切換時怎么恢復?依靠的就是程序計數(shù)器。
  •  JVM 的內存劃分與多線程是息息相關的。像我們程序中運行時用到的棧,以及本地方法棧,它們的維度都是線程。
  •  本地內存包含元數(shù)據(jù)區(qū)和一些直接內存。

虛擬機棧

Java 虛擬機棧是基于線程的。哪怕你只有一個 main() 方法,也是以線程的方式運行的。在線程的生命周期中,參與計算的數(shù)據(jù)會頻繁地入棧和出棧,棧的生命周期是和線程一樣的。

棧里的每條數(shù)據(jù),就是棧幀。在每個 Java 方法被調用的時候,都會創(chuàng)建一個棧幀,并入棧。一旦完成相應的調用,則出棧。所有的棧幀都出棧后,線程也就結束了。每個棧幀,都包含四個區(qū)域:

  •  局部變量表
  •  操作數(shù)棧
  •  動態(tài)連接
  •  返回地址 

我們的應用程序,就是在不斷操作這些內存空間中完成的。

本地方法棧是和虛擬機棧非常相似的一個區(qū)域,它服務的對象是 native 方法。你甚至可以認為虛擬機棧和本地方法棧是同一個區(qū)域,這并不影響我們對 JVM 的了解。

這里有一個比較特殊的數(shù)據(jù)類型叫作 returnAdress。因為這種類型只存在于字節(jié)碼層面,所以我們平常打交道的比較少。對于 JVM 來說,程序就是存儲在方法區(qū)的字節(jié)碼指令,而 returnAddress 類型的值就是指向特定指令內存地址的指針。

  •  這里有一個兩層的棧。第一層是棧幀,對應著方法;第二層是方法的執(zhí)行,對應著操作數(shù)。注意千萬不要搞混了。
  •  你可以看到,所有的字節(jié)碼指令,其實都會抽象成對棧的入棧出棧操作。執(zhí)行引擎只需要傻瓜式的按順序執(zhí)行,就可以保證它的正確性。

程序計數(shù)器

既然是線程,就代表它在獲取 CPU 時間片上,是不可預知的,需要有一個地方,對線程正在運行的點位進行緩沖記錄,以便在獲取 CPU 時間片時能夠快速恢復。

程序計數(shù)器是一塊較小的內存空間,它的作用可以看作是當前線程所執(zhí)行的字節(jié)碼的行號指示器。這里面存的,就是當前線程執(zhí)行的進度。下面這張圖,能夠加深大家對這個過程的理解。

可以看到,程序計數(shù)器也是因為線程而產(chǎn)生的,與虛擬機棧配合完成計算操作。程序計數(shù)器還存儲了當前正在運行的流程,包括正在執(zhí)行的指令、跳轉、分支、循環(huán)、異常處理等。

我們可以看一下程序計數(shù)器里面的具體內容。下面這張圖,就是使用 javap 命令輸出的字節(jié)碼。大家可以看到在每個 opcode 前面,都有一個序號。就是圖中紅框中的偏移地址,你可以認為它們是程序計數(shù)器的內容。

堆 

堆是 JVM 上最大的內存區(qū)域,我們申請的幾乎所有的對象,都是在這里存儲的。我們常說的垃圾回收,操作的對象就是堆。

堆空間一般是程序啟動時,就申請了,但是并不一定會全部使用。

隨著對象的頻繁創(chuàng)建,堆空間占用的越來越多,就需要不定期的對不再使用的對象進行回收。這個在 Java 中,就叫作 GC(Garbage Collection)。

由于對象的大小不一,在長時間運行后,堆空間會被許多細小的碎片占滿,造成空間浪費。所以,僅僅銷毀對象是不夠的,還需要堆空間整理。這個過程非常的復雜。

那一個對象創(chuàng)建的時候,到底是在堆上分配,還是在棧上分配呢?這和兩個方面有關:對象的類型和在 Java 類中存在的位置。

Java 的對象可以分為基本數(shù)據(jù)類型和普通對象。

對于普通對象來說,JVM 會首先在堆上創(chuàng)建對象,然后在其他地方使用的其實是它的引用。比如,把這個引用保存在虛擬機棧的局部變量表中。

對于基本數(shù)據(jù)類型來說(byte、short、int、long、float、double、char),有兩種情況。

我們上面提到,每個線程擁有一個虛擬機棧。當你在方法體內聲明了基本數(shù)據(jù)類型的對象,它就會在棧上直接分配。其他情況,都是在堆上分配。

注意,像 int[] 數(shù)組這樣的內容,是在堆上分配的。數(shù)組并不是基本數(shù)據(jù)類型。

這就是 JVM 的基本的內存分配策略。而堆是所有線程共享的,如果是多個線程訪問,會涉及數(shù)據(jù)同步問題。

元空間

關于元空間,我們還是以一個非常高頻的面試題開始:“為什么有 Metaspace 區(qū)域?它有什么問題?”

說到這里,你應該回想一下類與對象的區(qū)別。對象是一個活生生的個體,可以參與到程序的運行中;類更像是一個模版,定義了一系列屬性和操作。那么你可以設想一下。我們前面生成的 A.class,是放在 JVM 的哪個區(qū)域的?

想要問答這個問題,就不得不提下 Java 的歷史。在 Java 8 之前,這些類的信息是放在一個叫 Perm 區(qū)的內存里面的。更早版本,甚至 String.intern 相關的運行時常量池也放在這里。這個區(qū)域有大小限制,很容易造成 JVM 內存溢出,從而造成 JVM 崩潰。

Perm 區(qū)在 Java 8 中已經(jīng)被徹底廢除,取而代之的是 Metaspace。原來的 Perm 區(qū)是在堆上的,現(xiàn)在的元空間是在非堆上的,這是背景。關于它們的對比,可以看下這張圖。

然后,元空間的好處也是它的壞處。使用非堆可以使用操作系統(tǒng)的內存,JVM 不會再出現(xiàn)方法區(qū)的內存溢出;但是,無限制的使用會造成操作系統(tǒng)的死亡。所以,一般也會使用參數(shù) -XX:MaxMetaspaceSize 來控制大小。

方法區(qū),作為一個概念,依然存在。它的物理存儲的容器,就是 Metaspace。現(xiàn)在,只需要了解到,這個區(qū)域存儲的內容,包括:類的信息、常量池、方法數(shù)據(jù)、方法代碼就可以了。

小結

  •  我們常說的字符串常量,存放在哪呢?

由于常量池,在 Java 7 之后,放到了堆中,我們創(chuàng)建的字符串,將會在堆上分配。

  •  堆、非堆、本地內存,有什么關系?

關于它們的關系,我們可以看一張圖。在我的感覺里,堆是軟綿綿的,松散而有彈性;而非堆是冰冷生硬的,內存非常緊湊。

大家都知道,JVM 在運行時,會從操作系統(tǒng)申請大塊的堆內內存,進行數(shù)據(jù)的存儲。但是,堆外內存也就是申請后操作系統(tǒng)剩余的內存,也會有部分受到 JVM 的控制。比較典型的就是一些 native 關鍵詞修飾的方法,以及對內存的申請和處理。

在 Linux 機器上,使用 top 或者 ps 命令,在大多數(shù)情況下,能夠看到 RSS 段(實際的內存占用),是大于給 JVM 分配的堆內存的。

如果你申請了一臺系統(tǒng)內存為 2GB 的主機,可能 JVM 能用的就只有 1GB,這便是一個限制。

總結

JVM 的運行時區(qū)域是棧,而存儲區(qū)域是堆。很多變量,其實在編譯期就已經(jīng)固定了。 

 

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2023-12-04 08:01:05

2014-11-17 09:32:27

路由器

2018-10-31 12:44:39

網(wǎng)管路由器問題

2017-08-16 18:03:12

Docker安全工具容器

2022-01-27 07:39:57

進程操作系統(tǒng)Linux

2019-12-10 15:30:27

SaaSIaaS云計算

2019-06-06 16:13:14

JVMJava后端

2020-10-21 09:36:40

Vue項目技巧

2021-09-27 06:50:05

大數(shù)據(jù)旅游數(shù)據(jù)

2010-11-02 14:51:11

職場

2010-08-27 10:40:55

Android

2022-07-29 11:19:38

日志框架實踐

2019-12-24 14:04:59

PythonExcel數(shù)據(jù)處理

2021-04-12 08:56:00

多線程Future模式

2019-10-18 17:55:03

安全運營

2018-05-09 11:15:59

服務器緩存技巧

2019-11-27 14:20:27

Redis數(shù)據(jù)庫C語言

2020-09-22 08:16:20

軟件開發(fā)原則

2022-08-30 23:54:42

MySQL數(shù)據(jù)庫工具

2020-06-15 08:19:00

ZooKeeperEureka
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕一区在线观看视频 | 尤物视频在线免费观看 | 少妇精品亚洲一区二区成人 | 免费成人毛片 | 日本一区二区在线视频 | 久久久久免费 | 精品一区av | 国产欧美一区二区三区日本久久久 | 最新av中文字幕 | 日韩成人免费av | 91久久精品日日躁夜夜躁国产 | 国产日韩欧美精品一区二区三区 | 中文亚洲视频 | 免费福利视频一区二区三区 | 日韩免费在线视频 | 日本福利在线观看 | 少妇一级淫片免费放播放 | 国产一区二 | 一区欧美 | 亚洲欧美一区二区三区1000 | av影音资源| 国产中文字幕在线观看 | 日韩午夜网站 | 特级丰满少妇一级aaaa爱毛片 | 日日爱视频 | 免费观看视频www | 第一区在线观看免费国语入口 | 国产精品日韩欧美一区二区三区 | 蜜桃毛片| 欧美性tv| 欧产日产国产精品v | 丁香一区二区 | 综合二区 | 91影片| 久久成人精品视频 | 欧美综合一区二区三区 | 欧美久久国产 | 亚洲一区自拍 | 成人性视频在线播放 | 在线看av的网址 | 成人在线影视 |