JVM之內(nèi)存

1鬼店、JVM內(nèi)存區(qū)域

  • 方法區(qū)
  • 虛擬機(jī)棧
  • 本地方法棧
  • 程序計(jì)數(shù)器
image.png

方法區(qū)

??所有線程共享
所有對(duì)象實(shí)例及數(shù)組都需要在堆上分配(隨著棧上分配、標(biāo)量替換等师骗,也不那么絕對(duì)了)
??可以處于物理上不連續(xù)的內(nèi)存空間历等,當(dāng)堆中沒(méi)有內(nèi)存用于實(shí)例分配,堆也無(wú)法再擴(kuò)展時(shí)辟癌,拋出OutOfMemoryError異常寒屯。

虛擬機(jī)棧

??為虛擬機(jī)執(zhí)行Java方法(也就是字節(jié)碼)服務(wù)
??線程私有

  • 如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常
  • 如果虛擬機(jī)検蛏伲可以動(dòng)態(tài)擴(kuò)展寡夹,如果擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存处面,就會(huì)拋出OutOfMemoryError異常

本地方法棧

??為虛擬機(jī)執(zhí)行Native方法服務(wù)
??線程私有

  • 如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常
  • 如果虛擬機(jī)椧觯可以動(dòng)態(tài)擴(kuò)展鸳君,如果擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存,就會(huì)拋出OutOfMemoryError異常

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

??當(dāng)前線程所執(zhí)行的字節(jié)碼行號(hào)指示器

  • 若線程正在執(zhí)行的是Java方法患蹂,則為虛擬機(jī)字節(jié)碼指令地址
  • 若線程正在執(zhí)行的是Native方法,則為空
是唯一一個(gè)在Java虛擬機(jī)規(guī)范中沒(méi)有規(guī)定任何OutOfMemoryError情況的區(qū)域

2砸紊、對(duì)象的創(chuàng)建

  • 指針碰撞
    所有用過(guò)的內(nèi)存放在一邊传于,沒(méi)有用過(guò)的內(nèi)存放在另一邊。僅需要移動(dòng)中間的臨界點(diǎn)指針
  • 空閑列表
    通過(guò)列表記錄哪些內(nèi)存塊是可用的醉顽,在分配時(shí)從列表中找到足夠大的內(nèi)存
采用哪種方式由Java堆是否規(guī)整決定
Java堆是否規(guī)整由垃圾收集器是否帶壓縮整理功能決定

對(duì)象創(chuàng)建非常頻繁沼溜,存在并發(fā)問(wèn)題:

  • 方案一:對(duì)分配內(nèi)存空間的動(dòng)作進(jìn)行同步處理:虛擬機(jī)采用了CAS配上失敗重試的方式保證更新操作的原子性
  • 方案二:按照線程劃分不同的塊,每個(gè)線程在Java堆中預(yù)先分配一小塊內(nèi)存游添,成為本地線程分配緩沖(TLAB)

2系草、對(duì)象的訪問(wèn)

  • 句柄
  • 直接指針

內(nèi)存溢出:(out of memory)通俗理解就是內(nèi)存不夠,通常在運(yùn)行大型軟件或游戲時(shí)唆涝,軟件或游戲所需要的內(nèi)存遠(yuǎn)遠(yuǎn)超出了你主機(jī)內(nèi)安裝的內(nèi)存所承受大小找都,就叫內(nèi)存溢出。

內(nèi)存泄漏:(Memory Leak)是指程序中己動(dòng)態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無(wú)法釋放廊酣,造成系統(tǒng)內(nèi)存的浪費(fèi)能耻,導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果

如果是建立過(guò)多線程導(dǎo)致的內(nèi)存溢出,在不能減少線程數(shù)或更換64位虛擬機(jī)的情況下亡驰,就只能通過(guò)減少最大堆和減少棧容量來(lái)?yè)Q取更多的線程晓猛。

3、 GC算法

程序計(jì)數(shù)器凡辱、虛擬機(jī)棧戒职、本地方法棧不需要過(guò)多考慮回收的問(wèn)題

僅需關(guān)注Java堆和方法區(qū)

3.1對(duì)象存活還是死亡

  • 引用計(jì)數(shù)法
    很難解決對(duì)象間相互循環(huán)引用的問(wèn)題
  • 可達(dá)性分析算法
    使用“GCRoots對(duì)象”作為起點(diǎn)。
    可作為GC Roots對(duì)象:
    • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象
    • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象
    • 方法區(qū)中常量引用的對(duì)象
    • 本地方法棧中JNI(即一般說(shuō)的Native方法)引用的變量

3.1.1引用類型

http://www.reibang.com/p/825cca41d962

  • 強(qiáng)引用
    只要強(qiáng)引用存在透乾,被引用對(duì)象永遠(yuǎn)不會(huì)被回收
  • 軟引用 SoftReference
    系統(tǒng)在發(fā)生OOM之前洪燥,將這些對(duì)象列進(jìn)回收范圍,如果回收后依然沒(méi)有足夠內(nèi)存续徽,才拋出OOM
  • 弱引用 WeakReference
    對(duì)象僅會(huì)存活到下一次垃圾收集發(fā)生之前蚓曼。get方法可以訪問(wèn)被引用實(shí)例。
  • 虛引用
    對(duì)象僅會(huì)存活到下一次垃圾收集發(fā)生之前钦扭。get方法返回null纫版。為一個(gè)對(duì)象設(shè)置虛引用的唯一目的就是能在對(duì)象被回收時(shí)受到通知。

3.1.2對(duì)象死亡

對(duì)象真正死亡至少要經(jīng)歷兩次標(biāo)記過(guò)程

  1. 對(duì)象在可達(dá)性分析后沒(méi)有與GC Roots存在引用鏈客情,會(huì)被第一次標(biāo)記其弊。
  • 若對(duì)象沒(méi)有覆蓋finalize()方法或finalize()方法已被虛擬機(jī)調(diào)用過(guò)癞己,被認(rèn)為沒(méi)有必要執(zhí)行finalize()方法。
  • 其余均被認(rèn)為有必要執(zhí)行finalize()方法

2.有必要執(zhí)行finalize()方法的對(duì)象會(huì)被放入F-Queue隊(duì)列中梭伐,稍后被虛擬機(jī)建立的低優(yōu)先級(jí)的Finalize線程執(zhí)行痹雅。(虛擬機(jī)僅保證調(diào)用finalize方法,但不保證等待它執(zhí)行結(jié)束糊识,避免執(zhí)行緩慢绩社、死循環(huán)等)。
虛擬機(jī)會(huì)對(duì)F-Queue隊(duì)列中的對(duì)象進(jìn)行第二次標(biāo)記赂苗,如果對(duì)象在finalize方法中與引用鏈上的任何一個(gè)對(duì)象建立了關(guān)聯(lián)愉耙,則被移出待回收集合。

如果這之后對(duì)象仍然在待回收集合拌滋,則對(duì)象已死亡朴沿,等待垃圾回收。

任何對(duì)象的finalize方法僅會(huì)被調(diào)用一次败砂,之后再也不會(huì)被調(diào)用

方法區(qū)(永久代)的垃圾回收主要回收:廢棄常量+無(wú)用的類
廢棄常量與堆中的對(duì)象類似赌渣,沒(méi)有被引用則清出常量池
無(wú)用的類必須滿足:

  • 該類所有的實(shí)例都已被回收,java堆中不存在該類的任何實(shí)例
  • 加載該類的ClassLoader已經(jīng)被回收
  • 該類對(duì)應(yīng)的java.lang.Class對(duì)象沒(méi)有在任何地方被引用昌犹,無(wú)法在任何地方通過(guò)反射訪問(wèn)該類的方法
    滿足以上3個(gè)條件僅可以被回收坚芜,而不是必然被回收

4、 GC算法

4.1標(biāo)記-清除算法

標(biāo)記全部需回收對(duì)象祭隔,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象货岭。

  • 效率問(wèn)題:
    標(biāo)記和清除效率都不高
  • 空間問(wèn)題:
    產(chǎn)生大量不連續(xù)內(nèi)存碎片,導(dǎo)致分配大對(duì)象時(shí)不得不重新觸發(fā)GC

4.2復(fù)制算法(用于新生代)

將可用內(nèi)存分為大小相等的兩塊疾渴,每次只使用一塊千贯,GC時(shí)將存活的對(duì)象復(fù)制到另一塊。全部清除原來(lái)那半搞坝。
*空間問(wèn)題:
內(nèi)存浪費(fèi)搔谴,代價(jià)太高

由于新生代中98%的對(duì)象都是“朝生夕死”,并不需要1:1劃分內(nèi)存空間桩撮。
采用1塊較大的Eden空間和2塊較小的Survivor空間敦第。
每次使用1塊Eden和1塊Survivor空間,清理時(shí)將存活對(duì)象復(fù)制到1塊Survivor空間店量。全部清除原來(lái)的1塊Eden和1塊Survivor空間芜果。

當(dāng)Survivor空間不夠用時(shí),需要老年代進(jìn)行分配擔(dān)保融师。

4.3標(biāo)記-整理算法(用于老年代)

標(biāo)記全部需回收對(duì)象右钾,將所有存活對(duì)象向一端移動(dòng)。然后直接清理掉端邊界以外的內(nèi)存。

4.4分代收集算法

新生代采用復(fù)制算法舀射,老年代采用標(biāo)記-清除或標(biāo)記-整理算法窘茁。

5、 垃圾收集器

5.1Serial收集器

  • 僅用單線程完成垃圾收集工作
  • 進(jìn)行收集時(shí)脆烟,必須暫停其他所有工作線程

新生代單線程復(fù)制算法山林,暫停所有工作線程
老年代單線程標(biāo)記-整理算法,暫停所有工作線程

單CPU環(huán)境下邢羔,簡(jiǎn)單而高效

5.2 ParNew收集器

  • Serial收集器的多線程版本

新生代多線程復(fù)制算法驼抹,暫停所有工作線程
老年代單線程標(biāo)記-整理算法,暫停所有工作線程

僅Serial和ParNew收集器可以和CMS配合工作
因?yàn)镻arallel Scavenge和G1都沒(méi)有采用傳統(tǒng)的GC收集器代碼框架

5.3 Parallel Scavenge收集器(新生代收集器)

新生代多線程復(fù)制算法

Parallel Scavenge收集器的目的是達(dá)到一個(gè)可控制的吞吐量拜鹤。(CPU運(yùn)行用戶代碼時(shí)間/總時(shí)間)

  • 停頓時(shí)間短適合與用戶交互的程序
  • 高吞吐量適合高效利用CPU砂蔽,適合后臺(tái)運(yùn)算而不需要太多交互的任務(wù)

可設(shè)置兩個(gè)參數(shù)控制吞吐量:

  • 最大垃圾收集停頓時(shí)間
  • 直接設(shè)置吞吐量大小

需注意,GC停頓時(shí)間犧牲了吞吐量新生代空間署惯。
收集300M的新生代肯定比500M要快,但之前10秒收集一次每次100ms镣隶,現(xiàn)在5秒一次极谊,一次70ms,吞吐量也相應(yīng)下降安岂。

5.4 Serial Old收集器(老年代收集器)

  • Serial 收集器的老年代版本
    老年代采用單線程標(biāo)記-整理算法轻猖,暫停所有工作線程

  • 給Client模式下的虛擬機(jī)使用

  • 給Server模式下的虛擬機(jī)使用

    • 與Parallel Scavenge收集器配合使用
    • 作為CMS收集器的后備預(yù)案,在并發(fā)發(fā)生Concurrent Mode Failure時(shí)使用域那。

5.5 Parallel Old收集器(老年代收集器)

  • Parallel Scavenge收集器的老年代版本
    老年代采用多線程標(biāo)記-整理算法咙边,暫停所有工作線程

在注重吞吐量和CPU資源敏感的場(chǎng)合,都可以優(yōu)先考慮Parallel Scavenge+ Parallel Old的組合次员。

5.6 CMS收集器

*是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器

1.初始標(biāo)記败许,stop the world
2.并發(fā)標(biāo)記
3.重新標(biāo)記,stop the world
4.并發(fā)清除

  • 對(duì)CPU資源非常敏感淑蔚。
    并發(fā)時(shí)導(dǎo)致用戶進(jìn)程變慢市殷。CMS默認(rèn)啟動(dòng)線程數(shù)是(CPU數(shù)量+3)/4
  • 無(wú)法處理浮動(dòng)垃圾,可能出現(xiàn)Concurrent Mode Failure失敗而導(dǎo)致另一次Full GC的產(chǎn)生刹衫。
    因?yàn)槔占A段用戶線程還是繼續(xù)運(yùn)行醋寝。
    CMS不能等到老年代幾乎完全被填滿再開(kāi)始收集,若收集過(guò)程中預(yù)留的內(nèi)存無(wú)法滿足程序需要带迟,則會(huì)出現(xiàn)Current Mode Failure失敗音羞。虛擬機(jī)臨時(shí)啟動(dòng)后備預(yù)案Serial Old
  • CMS基于標(biāo)記-清除算法,會(huì)有大量空間碎片產(chǎn)生仓犬。

5.7 G1收集器

1.初始標(biāo)記
2.并發(fā)標(biāo)記
3.最終標(biāo)記
4.篩選回收

G1將Java堆劃分為多個(gè)大小相等的區(qū)域嗅绰。新生代老年代不再物理隔離。
在后臺(tái)維護(hù)一個(gè)優(yōu)先列表,每次根據(jù)允許的收集時(shí)間办陷,優(yōu)先回收價(jià)值最大的Region貌夕。

  • 并行與并發(fā)
  • 分代收集
  • 空間整合
  • 可預(yù)測(cè)的停頓

6、 內(nèi)存分配

6.1 對(duì)象優(yōu)先在Eden區(qū)分配

Eden區(qū)沒(méi)有足夠空間時(shí)民镜,出發(fā)Minor GC
(新生代Minor GC
老年代Major GC / Full GC啡专,一般比Minor GC慢10倍以上)

6.2 大對(duì)象直接進(jìn)入老年代

常見(jiàn)的很長(zhǎng)的字符串和數(shù)組

6.3 長(zhǎng)期存活的對(duì)象進(jìn)入老年代

對(duì)象在Eden區(qū)出生并經(jīng)歷一次Minor GC后仍能被Survivor容納的話,記為1歲制圈,移動(dòng)代Survivor中们童。
每經(jīng)歷一次Minor GC就增加1歲。
當(dāng)年齡增加到一定程度(默認(rèn)15歲)鲸鹦,就會(huì)被晉升到老年代中慧库。

6.4 動(dòng)態(tài)對(duì)象年齡判斷

如果在Survivor空間中相同年齡所有對(duì)象大小總和大于Survivor空間的一半,則年齡大于或等于該年齡的對(duì)象就直接進(jìn)入老年代馋嗜,無(wú)需等到要求的年齡齐板。

6.5 空間分配擔(dān)保

在Minor GC前,檢查老年代最大可用連續(xù)空間是否大于新生代空間總和葛菇。若大于則Minor GC可以安全進(jìn)行甘磨。否則,則查看是否允許擔(dān)保失敗眯停。若允許擔(dān)保失敗济舆,則查看老年代最大可用連續(xù)空間是否大于歷次新生代晉升到老年代的平均大小。如果大于則嘗試進(jìn)行Minor GC(雖然有風(fēng)險(xiǎn))莺债,否則進(jìn)行Full GC滋觉。

SafePoint

由于 Full GC(或Minor GC) 會(huì)影響性能,所以我們要在一個(gè)合適的時(shí)間點(diǎn)發(fā)起 GC齐邦,這個(gè)時(shí)間點(diǎn)被稱為 Safe Point椎侠,這個(gè)時(shí)間點(diǎn)的選定既不能太少以讓 GC 時(shí)間太長(zhǎng)導(dǎo)致程序過(guò)長(zhǎng)時(shí)間卡頓,也不能過(guò)于頻繁以至于過(guò)分增大運(yùn)行時(shí)的負(fù)荷侄旬。一般當(dāng)線程在這個(gè)時(shí)間點(diǎn)上狀態(tài)是可以確定的肺蔚,如確定 GC Root 的信息等,可以使 JVM 開(kāi)始安全地 GC儡羔。Safe Point 主要指的是以下特定位置:

循環(huán)的末尾
方法返回前
調(diào)用方法的 call 之后
拋出異常的位置 另外需要注意的是由于新生代的特點(diǎn)(大部分對(duì)象經(jīng)過(guò) Minor GC后會(huì)消亡)宣羊, Minor GC 用的是復(fù)制算法,而在老生代由于對(duì)象比較多汰蜘,占用的空間較大仇冯,使用復(fù)制算法會(huì)有較大開(kāi)銷(復(fù)制算法在對(duì)象存活率較高時(shí)要進(jìn)行多次復(fù)制操作,同時(shí)浪費(fèi)一半空間)所以根據(jù)老生代特點(diǎn)族操,在老年代進(jìn)行的 GC 一般采用的是標(biāo)記整理法來(lái)進(jìn)行回收苛坚。

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末比被,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子泼舱,更是在濱河造成了極大的恐慌等缀,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娇昙,死亡現(xiàn)場(chǎng)離奇詭異尺迂,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)冒掌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門噪裕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人股毫,你說(shuō)我怎么就攤上這事膳音。” “怎么了铃诬?”我有些...
    開(kāi)封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵祭陷,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我趣席,道長(zhǎng)颗胡,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任吩坝,我火速辦了婚禮,結(jié)果婚禮上哑蔫,老公的妹妹穿的比我還像新娘钉寝。我一直安慰自己,他們只是感情好闸迷,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布嵌纲。 她就那樣靜靜地躺著,像睡著了一般腥沽。 火紅的嫁衣襯著肌膚如雪逮走。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天今阳,我揣著相機(jī)與錄音师溅,去河邊找鬼。 笑死盾舌,一個(gè)胖子當(dāng)著我的面吹牛墓臭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播妖谴,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼窿锉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起嗡载,我...
    開(kāi)封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤窑多,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后洼滚,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體埂息,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年判沟,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了耿芹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡挪哄,死狀恐怖吧秕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情迹炼,我是刑警寧澤砸彬,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站斯入,受9級(jí)特大地震影響砂碉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜刻两,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一增蹭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧磅摹,春花似錦滋迈、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至帝美,卻和暖如春碍彭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悼潭。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工庇忌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舰褪。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓漆枚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親抵知。 傳聞我的和親對(duì)象是個(gè)殘疾皇子墙基,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • ??內(nèi)存是非常重要的系統(tǒng)資源软族,是硬盤和CPU的中間倉(cāng)庫(kù)及橋梁,承載著操作系統(tǒng)和應(yīng)用程序的實(shí)時(shí)運(yùn)行残制。JVM內(nèi)存布局規(guī)...
    Coder慌閱讀 1,002評(píng)論 0 1
  • 1. 五大內(nèi)存區(qū)域 1.1 程序計(jì)數(shù)器 程序計(jì)數(shù)器是一塊很小的內(nèi)存空間立砸,它是線程私有的,可以認(rèn)作為當(dāng)前線程的行號(hào)指...
    一只老實(shí)的程序猿閱讀 277評(píng)論 0 0
  • Java和C++之間有一堵由內(nèi)存動(dòng)態(tài)分配和垃圾收集技術(shù)所圍成的“高墻”初茶,墻外面的人想進(jìn)來(lái)颗祝,墻里面的人想出來(lái)。 對(duì)象...
    胡二囧閱讀 1,076評(píng)論 0 4
  • JVM架構(gòu) 當(dāng)一個(gè)程序啟動(dòng)之前恼布,它的class會(huì)被類裝載器裝入方法區(qū)(Permanent區(qū))螺戳,執(zhí)行引擎讀取方法區(qū)的...
    cocohaifang閱讀 1,646評(píng)論 0 7
  • 偶得一日清閑 靜謐清晨稍顯散漫 此刻靜好 無(wú)有閑人騷擾 憶起昨夜夢(mèng)祈 此地可 隨心 隨性 隨欲落筆與墨歡好 忘卻紅...
    墨竹蘭韻閱讀 109評(píng)論 1 0