Java GC全集(十二):Weak, Soft 及 Phantom 引用詳解

本文來自于HeapDump性能社區(qū)! 欣尼!有性能問題拓提,上HeapDump性能社區(qū)!
正文:

Weak, Soft 及 Phantom 引用

另一類影響GC的問題是程序中的 non-strong 引用鸿吆。雖然這類引用在很多情況下可以避免出現(xiàn) OutOfMemoryError, 但過量使用也會(huì)對(duì)GC造成嚴(yán)重的影響, 反而降低系統(tǒng)性能囤采。

1,弱引用的缺點(diǎn)

首先, 弱引用(weak reference) 是可以被GC強(qiáng)制回收的惩淳。當(dāng)垃圾收集器發(fā)現(xiàn)一個(gè)弱可達(dá)對(duì)象(weakly reachable,即指向該對(duì)象的引用只剩下弱引用) 時(shí), 就會(huì)將其置入相應(yīng)的ReferenceQueue 中, 變成可終結(jié)的對(duì)象. 之后可能會(huì)遍歷這個(gè) reference queue, 并執(zhí)行相應(yīng)的清理蕉毯。典型的示例是清除緩存中不再引用的KEY。

當(dāng)然, 在這個(gè)時(shí)候, 我們還可以將該對(duì)象賦值給新的強(qiáng)引用, 在最后終結(jié)和回收前, GC會(huì)再次確認(rèn)該對(duì)象是否可以安全回收思犁。因此, 弱引用對(duì)象的回收過程是橫跨多個(gè)GC周期的代虾。

實(shí)際上弱引用使用的很多。大部分緩存框架(caching solution)都是基于弱引用實(shí)現(xiàn)的, 所以雖然業(yè)務(wù)代碼中沒有直接使用弱引用, 但程序中依然會(huì)大量存在激蹲。

其次, 軟引用(soft reference) 比弱引用更難被垃圾收集器回收. 回收軟引用沒有確切的時(shí)間點(diǎn), 由JVM自己決定. 一般只會(huì)在即將耗盡可用內(nèi)存時(shí), 才會(huì)回收軟引用,以作最后手段棉磨。這意味著, 可能會(huì)有更頻繁的 full GC, 暫停時(shí)間也比預(yù)期更長(zhǎng), 因?yàn)槔夏甏械拇婊顚?duì)象會(huì)很多。

最后, 使用虛引用(phantom reference)時(shí), 必須手動(dòng)進(jìn)行內(nèi)存管理, 以標(biāo)識(shí)這些對(duì)象是否可以安全地回收学辱。表面上看起來很正常, 但實(shí)際上并不是這樣乘瓤。 javadoc 中寫道:

In order to ensure that a reclaimable object remains so, the referent of a phantom reference may not be retrieved: The get method of a phantom reference always returns null.

為了防止可回收對(duì)象的殘留, 虛引用對(duì)象不應(yīng)該被獲取: phantom referenceget 方法返回值永遠(yuǎn)是 null

令人驚訝的是, 很多開發(fā)者忽略了下一段內(nèi)容(這才是重點(diǎn)):

Unlike soft and weak references, phantom references are not automatically cleared by the garbage collector as they are enqueued. An object that is reachable via phantom references will remain so until all such references are cleared or themselves become unreachable.

與軟引用和弱引用不同, 虛引用不會(huì)被 GC 自動(dòng)清除, 因?yàn)樗麄儽淮娣诺疥?duì)列中. 通過虛引用可達(dá)的對(duì)象會(huì)繼續(xù)留在內(nèi)存中, 直到調(diào)用此引用的 clear 方法, 或者引用自身變?yōu)椴豢蛇_(dá)策泣。

也就是說,我們必須手動(dòng)調(diào)用 clear() 來清除虛引用, 否則可能會(huì)造成 OutOfMemoryError 而導(dǎo)致 JVM 掛掉. 使用虛引用的理由是, 對(duì)于用編程手段來跟蹤某個(gè)對(duì)象何時(shí)變?yōu)椴豢蛇_(dá)對(duì)象, 這是唯一的常規(guī)手段芹助。 和軟引用/弱引用不同的是, 我們不能復(fù)活虛可達(dá)(phantom-reachable)對(duì)象沙郭。

2弛针,舉個(gè)例子

讓我們看一個(gè)弱引用示例, 其中創(chuàng)建了大量的對(duì)象, 并在 minor GC 中完成回收冀宴。和前面一樣, 修改提升閥值。使用的JVM參數(shù)為: -Xmx24m -XX:NewSize=16m -XX:MaxTenuringThreshold=1 , GC日志如下所示:

2.330: [GC (Allocation Failure) 20933K->8229K(22528K), 0.0033848 secs]
2.335: [GC (Allocation Failure) 20517K->7813K(22528K), 0.0022426 secs]
2.339: [GC (Allocation Failure) 20101K->7429K(22528K), 0.0010920 secs]
2.341: [GC (Allocation Failure) 19717K->9157K(22528K), 0.0056285 secs]
2.348: [GC (Allocation Failure) 21445K->8997K(22528K), 0.0041313 secs]
2.354: [GC (Allocation Failure) 21285K->8581K(22528K), 0.0033737 secs]
2.359: [GC (Allocation Failure) 20869K->8197K(22528K), 0.0023407 secs]
2.362: [GC (Allocation Failure) 20485K->7845K(22528K), 0.0011553 secs]
2.365: [GC (Allocation Failure) 20133K->9501K(22528K), 0.0060705 secs]
2.371: [Full GC (Ergonomics) 9501K->2987K(22528K), 0.0171452 secs]

可以看到, Full GC 的次數(shù)很少危队。但如果使用弱引用來指向創(chuàng)建的對(duì)象, 使用JVM參數(shù) -Dweak.refs=true, 則情況會(huì)發(fā)生明顯變化. 使用弱引用的原因很多, 比如在 weak hash map 中將對(duì)象作為Key的情況蓄喇。在任何情況下, 使用弱引用都可能會(huì)導(dǎo)致以下情形:

2.059: [Full GC (Ergonomics) 20365K->19611K(22528K), 0.0654090 secs]
2.125: [Full GC (Ergonomics) 20365K->19711K(22528K), 0.0707499 secs]
2.196: [Full GC (Ergonomics) 20365K->19798K(22528K), 0.0717052 secs]
2.268: [Full GC (Ergonomics) 20365K->19873K(22528K), 0.0686290 secs]
2.337: [Full GC (Ergonomics) 20365K->19939K(22528K), 0.0702009 secs]
2.407: [Full GC (Ergonomics) 20365K->19995K(22528K), 0.0694095 secs]

可以看到, 發(fā)生了多次 full GC, 比起前一節(jié)的示例, GC時(shí)間增加了一個(gè)數(shù)量級(jí)! 這是過早提升的另一個(gè)例子, 但這次情況更加棘手. 當(dāng)然,問題的根源在于弱引用。這些臨死的對(duì)象, 在添加弱引用之后, 被提升到了老年代交掏。 但是, 他們現(xiàn)在陷入另一次GC循環(huán)之中, 所以需要對(duì)其做一些適當(dāng)?shù)那謇怼O裰耙粯? 最簡(jiǎn)單的辦法是增加年輕代的大小, 例如指定JVM參數(shù): -Xmx64m -XX:NewSize=32m:

2.328: [GC (Allocation Failure) 38940K->13596K(61440K), 0.0012818 secs]
2.332: [GC (Allocation Failure) 38172K->14812K(61440K), 0.0060333 secs]
2.341: [GC (Allocation Failure) 39388K->13948K(61440K), 0.0029427 secs]
2.347: [GC (Allocation Failure) 38524K->15228K(61440K), 0.0101199 secs]
2.361: [GC (Allocation Failure) 39804K->14428K(61440K), 0.0040940 secs]
2.368: [GC (Allocation Failure) 39004K->13532K(61440K), 0.0012451 secs]

這時(shí)候, 對(duì)象在 minor GC 中就被回收了刃鳄。

更壞的情況是使用軟引用,例如這個(gè)軟引用示例程序盅弛。如果程序不是即將發(fā)生 OutOfMemoryError , 軟引用對(duì)象就不會(huì)被回收. 在示例程序中,用軟引用替代弱引用, 立即出現(xiàn)了更多的 Full GC 事件:

2.162: [Full GC (Ergonomics) 31561K->12865K(61440K), 0.0181392 secs]
2.184: [GC (Allocation Failure) 37441K->17585K(61440K), 0.0024479 secs]
2.189: [GC (Allocation Failure) 42161K->27033K(61440K), 0.0061485 secs]
2.195: [Full GC (Ergonomics) 27033K->14385K(61440K), 0.0228773 secs]
2.221: [GC (Allocation Failure) 38961K->20633K(61440K), 0.0030729 secs]
2.227: [GC (Allocation Failure) 45209K->31609K(61440K), 0.0069772 secs]
2.234: [Full GC (Ergonomics) 31609K->15905K(61440K), 0.0257689 secs]

最有趣的是虛引用示例中的虛引用, 使用同樣的JVM參數(shù)啟動(dòng), 其結(jié)果和弱引用示例非常相似。實(shí)際上, full GC 暫停的次數(shù)會(huì)小得多, 原因前面說過, 他們有不同的終結(jié)方式。

如果禁用虛引用清理, 增加JVM啟動(dòng)參數(shù) (-Dno.ref.clearing=true), 則可以看到:

4.180: [Full GC (Ergonomics) 57343K->57087K(61440K), 0.0879851 secs]
4.269: [Full GC (Ergonomics) 57089K->57088K(61440K), 0.0973912 secs]
4.366: [Full GC (Ergonomics) 57091K->57089K(61440K), 0.0948099 secs]

main 線程中拋出異常 java.lang.OutOfMemoryError: Java heap space.

使用虛引用時(shí)要小心謹(jǐn)慎, 并及時(shí)清理虛可達(dá)對(duì)象挪鹏。如果不清理, 很可能會(huì)發(fā)生 OutOfMemoryError. 請(qǐng)相信我們的經(jīng)驗(yàn)教訓(xùn): 處理 reference queue 的線程中如果沒 catch 住 exception , 系統(tǒng)很快就會(huì)被整掛了见秽。

使用非強(qiáng)引用的影響

建議使用JVM參數(shù) -XX:+PrintReferenceGC 來看看各種引用對(duì)GC的影響. 如果將此參數(shù)用于啟動(dòng) 弱引用示例 , 將會(huì)看到:

2.173: [Full GC (Ergonomics)
2.234: [SoftReference, 0 refs, 0.0000151 secs]
2.234: [WeakReference, 2648 refs, 0.0001714 secs]
2.234: [FinalReference, 1 refs, 0.0000037 secs]
2.234: [PhantomReference, 0 refs, 0 refs, 0.0000039 secs]
2.234: [JNI Weak Reference, 0.0000027 secs]
[PSYoungGen: 9216K->8676K(10752K)]
[ParOldGen: 12115K->12115K(12288K)]
21331K->20792K(23040K),
[Metaspace: 3725K->3725K(1056768K)],
0.0766685 secs]
[Times: user=0.49 sys=0.01, real=0.08 secs]
2.250: [Full GC (Ergonomics)
2.307: [SoftReference, 0 refs, 0.0000173 secs]
2.307: [WeakReference, 2298 refs, 0.0001535 secs]
2.307: [FinalReference, 3 refs, 0.0000043 secs]
2.307: [PhantomReference, 0 refs, 0 refs, 0.0000042 secs]
2.307: [JNI Weak Reference, 0.0000029 secs]
[PSYoungGen: 9215K->8747K(10752K)]
[ParOldGen: 12115K->12115K(12288K)]
21331K->20863K(23040K),
[Metaspace: 3725K->3725K(1056768K)],
0.0734832 secs]
[Times: user=0.52 sys=0.01, real=0.07 secs]
2.323: [Full GC (Ergonomics)
2.383: [SoftReference, 0 refs, 0.0000161 secs]
2.383: [WeakReference, 1981 refs, 0.0001292 secs]
2.383: [FinalReference, 16 refs, 0.0000049 secs]
2.383: [PhantomReference, 0 refs, 0 refs, 0.0000040 secs]
2.383: [JNI Weak Reference, 0.0000027 secs]
[PSYoungGen: 9216K->8809K(10752K)]
[ParOldGen: 12115K->12115K(12288K)]
21331K->20925K(23040K),
[Metaspace: 3725K->3725K(1056768K)],
0.0738414 secs]
[Times: user=0.52 sys=0.01, real=0.08 secs]

只有確定 GC 對(duì)應(yīng)用的吞吐量和延遲造成影響之后, 才應(yīng)該花心思來分析這些信息, 審查這部分日志。通常情況下, 每次GC清理的引用數(shù)量都是很少的, 大部分情況下為 0讨盒。如果GC 花了較多時(shí)間來清理這類引用, 或者清除了很多的此類引用, 就需要進(jìn)一步觀察和分析了解取。

解決方案

如果程序確實(shí)碰到了 mis-, ab- 問題或者濫用 weak, soft, phantom 引用, 一般都要修改程序的實(shí)現(xiàn)邏輯。每個(gè)系統(tǒng)不一樣, 因此很難提供通用的指導(dǎo)建議, 但有一些常用的辦法:

  • 弱引用(Weak references) —— 如果某個(gè)內(nèi)存池的使用量增大, 造成了性能問題, 那么增加這個(gè)內(nèi)存池的大小(可能也要增加堆內(nèi)存的最大容量)返顺。如同示例中所看到的, 增加堆內(nèi)存的大小, 以及年輕代的大小, 可以減輕癥狀禀苦。
  • 虛引用(Phantom references) —— 請(qǐng)確保在程序中調(diào)用了虛引用的 clear 方法。編程中很容易忽略某些虛引用, 或者清理的速度跟不上生產(chǎn)的速度, 又或者清除引用隊(duì)列的線程掛了, 就會(huì)對(duì)GC 造成很大壓力, 最終可能引起 OutOfMemoryError遂鹊。
  • 軟引用(Soft references) —— 如果確定問題的根源是軟引用, 唯一的解決辦法是修改程序源碼, 改變內(nèi)部實(shí)現(xiàn)邏輯振乏。

3,其他示例

前面介紹了最常見的GC性能問題秉扑。但我們學(xué)到的很多原理都沒有具體的場(chǎng)景來展現(xiàn)慧邮。本節(jié)介紹一些不常發(fā)生, 但也可能會(huì)碰到的問題。

RMI 與 GC

如果系統(tǒng)提供或者消費(fèi) RMI 服務(wù), 則JVM會(huì)定期執(zhí)行 full GC 來確保本地未使用的對(duì)象在另一端也不占用空間. 記住, 即使你的代碼中沒有發(fā)布 RMI 服務(wù), 但第三方或者工具庫(kù)也可能會(huì)打開 RMI 終端. 最常見的元兇是 JMX, 如果通過JMX連接到遠(yuǎn)端, 底層則會(huì)使用 RMI 發(fā)布數(shù)據(jù)舟陆。

問題是有很多不必要的周期性 full GC误澳。查看老年代的使用情況, 一般是沒有內(nèi)存壓力, 其中還存在大量的空閑區(qū)域, 但 full GC 就是被觸發(fā)了, 也就會(huì)暫停所有的應(yīng)用線程。

這種周期性調(diào)用 System.gc() 刪除遠(yuǎn)程引用的行為, 是在 sun.rmi.transport.ObjectTable 類中, 通過 sun.misc.GC.requestLatency(long gcInterval) 調(diào)用的秦躯。

對(duì)許多應(yīng)用來說, 根本沒必要, 甚至對(duì)性能有害忆谓。 禁止這種周期性的 GC 行為, 可以使用以下 JVM 參數(shù):

java -Dsun.rmi.dgc.server.gcInterval=9223372036854775807L 
    -Dsun.rmi.dgc.client.gcInterval=9223372036854775807L 
    com.yourcompany.YourApplication

這讓 Long.MAX_VALUE 毫秒之后, 才調(diào)用 System.gc(), 實(shí)際運(yùn)行的系統(tǒng)可能永遠(yuǎn)都不會(huì)觸發(fā)。

ObjectTable.class

private static final long gcInterval =
((Long)AccessController.doPrivileged(
new GetLongAction("sun.rmi.dgc.server.gcInterval", 3600000L)
)).longValue();

可以看到, 默認(rèn)值為 3600000L,也就是1小時(shí)觸發(fā)一次 Full GC宦赠。

另一種方式是指定JVM參數(shù) -XX:+DisableExplicitGC, 禁止顯式地調(diào)用 System.gc(). 但我們強(qiáng)烈反對(duì) 這種方式, 因?yàn)槁裼械乩住?/p>

JVMTI tagging 與 GC

如果在程序啟動(dòng)時(shí)指定了 Java Agent (-javaagent), agent 就可以使用 JVMTI tagging 標(biāo)記堆中的對(duì)象陪毡。agent 使用tagging的種種原因本手冊(cè)不詳細(xì)講解, 但如果 tagging 標(biāo)記了大量的對(duì)象, 很可能會(huì)引起 GC 性能問題, 導(dǎo)致延遲增加, 以及吞吐量降低。

問題發(fā)生在 native 代碼中, JvmtiTagMap::do_weak_oops 在每次GC時(shí), 都會(huì)遍歷所有標(biāo)簽(tag),并執(zhí)行一些比較耗時(shí)的操作勾扭。更坑的是, 這種操作是串行執(zhí)行的毡琉。

如果存在大量的標(biāo)簽, 就意味著 GC 時(shí)有很大一部分工作是單線程執(zhí)行的, GC暫停時(shí)間可能會(huì)增加一個(gè)數(shù)量級(jí)。

檢查是否因?yàn)?agent 增加了GC暫停時(shí)間, 可以使用診斷參數(shù) –XX:+TraceJVMTIObjectTagging. 啟用跟蹤之后, 可以估算出內(nèi)存中 tag 映射了多少 native 內(nèi)存, 以及遍歷所消耗的時(shí)間妙色。

如果你不是 agent 的作者, 那一般是搞不定這類問題的桅滋。除了提BUG之外你什么都做不了. 如果發(fā)生了這種情況, 請(qǐng)建議廠商清理不必要的標(biāo)簽。

巨無霸對(duì)象的分配(Humongous Allocations)

如果使用 G1 垃圾收集算法, 會(huì)產(chǎn)生一種巨無霸對(duì)象引起的 GC 性能問題身辨。

說明: 在G1中, 巨無霸對(duì)象是指所占空間超過一個(gè)小堆區(qū)(region) 50% 的對(duì)象丐谋。

頻繁的創(chuàng)建巨無霸對(duì)象, 無疑會(huì)造成GC的性能問題, 看看G1的處理方式:

  • 如果某個(gè) region 中含有巨無霸對(duì)象, 則巨無霸對(duì)象后面的空間將不會(huì)被分配。如果所有巨無霸對(duì)象都超過某個(gè)比例, 則未使用的空間就會(huì)引發(fā)內(nèi)存碎片問題煌珊。
  • G1 沒有對(duì)巨無霸對(duì)象進(jìn)行優(yōu)化号俐。這在 JDK 8 以前是個(gè)特別棘手的問題 —— 在 Java 1.8u40 之前的版本中, 巨無霸對(duì)象所在 region 的回收只能在 full GC 中進(jìn)行。最新版本的 Hotspot JVM, 在 marking 階段之后的 cleanup 階段中釋放巨無霸區(qū)間, 所以這個(gè)問題在新版本JVM中的影響已大大降低定庵。

要監(jiān)控是否存在巨無霸對(duì)象, 可以打開GC日志, 使用的命令如下:

java -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
-XX:+PrintReferenceGC -XX:+UseG1GC
-XX:+PrintAdaptiveSizePolicy -Xmx128m
MyClass

GC 日志中可能會(huì)發(fā)現(xiàn)這樣的部分:

0.106: [G1Ergonomics (Concurrent Cycles)
request concurrent cycle initiation,
reason: occupancy higher than threshold,
occupancy: 60817408 bytes,
allocation request: 1048592 bytes,
threshold: 60397965 bytes (45.00 %),
source: concurrent humongous allocation]
0.106: [G1Ergonomics (Concurrent Cycles)
request concurrent cycle initiation,
reason: requested by GC cause,
GC cause: G1 Humongous Allocation]
0.106: [G1Ergonomics (Concurrent Cycles)
initiate concurrent cycle,
reason: concurrent cycle initiation requested]
0.106: [GC pause (G1 Humongous Allocation)
(young) (initial-mark)
0.106: [G1Ergonomics (CSet Construction)
start choosing CSet,
_pending_cards: 0,
predicted base
time: 10.00 ms,
remaining time: 190.00 ms,
target pause time: 200.00 ms]

這樣的日志就是證據(jù), 表明程序中確實(shí)創(chuàng)建了巨無霸對(duì)象. 可以看到: G1 Humongous Allocation 是 GC暫停的原因吏饿。 再看前面一點(diǎn)的 allocation request: 1048592 bytes , 可以發(fā)現(xiàn)程序試圖分配一個(gè) 1,048,592 字節(jié)的對(duì)象, 這要比巨無霸區(qū)域(2MB)的 50% 多出 16 個(gè)字節(jié)踪危。

第一種解決方式, 是修改 region size , 以使得大多數(shù)的對(duì)象不超過 50%, 也就不進(jìn)行巨無霸對(duì)象區(qū)域的分配。 region 的默認(rèn)大小在啟動(dòng)時(shí)根據(jù)堆內(nèi)存的大小算出猪落。但也可以指定參數(shù)來覆蓋默認(rèn)設(shè)置, -XX:G1HeapRegionSize=XX贞远。 指定的 region size 必須在 1~32MB 之間, 還必須是2的冪 【2^10 = 1024 = 1KB; 2^20=1MB; 所以 region size 只能是: 1m,2m,4m,8m,16m,32m】。

這種方式也有副作用, 增加 region 的大小也就變相地減少了 region 的數(shù)量, 所以需要謹(jǐn)慎使用, 最好進(jìn)行一些測(cè)試, 看看是否改善了吞吐量和延遲笨忌。

更好的方式需要一些工作量, 如果可以的話, 在程序中限制對(duì)象的大小蓝仲。最好是使用分析器, 展示出巨無霸對(duì)象的信息, 以及分配時(shí)所在的堆棧跟蹤信息。

總結(jié)

JVM上運(yùn)行的程序多種多樣, 啟動(dòng)參數(shù)也有上百個(gè), 其中有很多會(huì)影響到 GC, 所以調(diào)優(yōu)GC性能的方法也有很多種官疲。

還是那句話, 沒有真正的銀彈, 能滿足所有的性能調(diào)優(yōu)指標(biāo)袱结。 我們能做的只是介紹一些常見的/和不常見的示例, 讓你在碰到類似問題時(shí)知道是怎么回事。深入理解GC的工作原理, 熟練應(yīng)用各種工具, 就可以進(jìn)行GC調(diào)優(yōu), 提高程序性能袁余。

在本系列文章中,介紹了JVM中垃圾收集的實(shí)現(xiàn)原理擎勘,以及如何高效地利用GC。
第一篇:什么是垃圾回收颖榜?

第二篇:Java 中的垃圾收集原理解析

第三篇:GC算法基礎(chǔ)篇

第四篇:GC 算法實(shí)現(xiàn)篇——串行GC

第五篇:GC 算法實(shí)現(xiàn)篇——并行GC

第六篇:GC 算法實(shí)現(xiàn)篇——并發(fā)標(biāo)記-清除

第七篇:GC 算法實(shí)現(xiàn)篇——垃圾優(yōu)先算法

第八篇:GC 調(diào)優(yōu)基礎(chǔ)篇

第九篇:GC 調(diào)優(yōu)工具篇

第十篇:GC調(diào)優(yōu)實(shí)戰(zhàn)篇—高分配速率(High Allocation Rate)

第十一篇:GC 調(diào)優(yōu)的實(shí)戰(zhàn)篇—過早提升(Premature Promotion)

第十二篇:GC 調(diào)優(yōu)的實(shí)戰(zhàn)篇—Weak, Soft 及 Phantom 引用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棚饵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子掩完,更是在濱河造成了極大的恐慌噪漾,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件且蓬,死亡現(xiàn)場(chǎng)離奇詭異欣硼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)恶阴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門诈胜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人冯事,你說我怎么就攤上這事焦匈。” “怎么了昵仅?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵缓熟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我摔笤,道長(zhǎng)够滑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任吕世,我火速辦了婚禮彰触,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘命辖。我一直安慰自己渴析,他們只是感情好晚伙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俭茧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪漓帚。 梳的紋絲不亂的頭發(fā)上母债,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音尝抖,去河邊找鬼毡们。 笑死,一個(gè)胖子當(dāng)著我的面吹牛昧辽,可吹牛的內(nèi)容都是我干的衙熔。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼搅荞,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼红氯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咕痛,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤痢甘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后茉贡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體塞栅,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年腔丧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了放椰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡愉粤,死狀恐怖砾医,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情科汗,我是刑警寧澤藻烤,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站头滔,受9級(jí)特大地震影響怖亭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坤检,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一兴猩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧早歇,春花似錦倾芝、人聲如沸讨勤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)潭千。三九已至,卻和暖如春借尿,著一層夾襖步出監(jiān)牢的瞬間刨晴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工路翻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狈癞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓茂契,卻偏偏與公主長(zhǎng)得像蝶桶,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掉冶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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