2023-12-14

jvm相關(guān)

內(nèi)存區(qū)域分布
共享區(qū)域:

堆:存儲java的實例
方法區(qū):靜態(tài)變量,類的信息刺桃,常量池

線程私有區(qū)域:

程序計數(shù)器:記錄正在執(zhí)行的字節(jié)碼指令地址
方法棧:用于存儲局部變量表携添、操作數(shù)棧羽戒、動態(tài)鏈接勺远、方法出口等信息首尼。
本地方法堆棧:針對的是 Native 方法

Gc原理和回收策略

回收區(qū)域:只針對堆蝶锋、方法區(qū)陆爽;線程私有區(qū)域數(shù)據(jù)會隨線程結(jié)束銷毀,不用回收
回收類型:1.堆中的對象:分代收集 GC 方法會吧堆劃分為新生代扳缕、老年代慌闭。新生代:新建小對象會進入新生代别威;通過復制算法回收對象;老年代:新建大對象及老對象會進入老年代驴剔;通過標記-清除算法回收對象省古。
2.方法區(qū)中的類信息、常量池
判斷一個對象是否可被回收:
1.引用計數(shù)法:有循環(huán)引用的缺點
2.可達性分析法:從 GC ROOT 開始搜索丧失,不可達的對象都是可以被回收的豺妓。其中 GC ROOT 包括虛擬機棧/本地方法棧中引用的對象、方法區(qū)中常量/靜態(tài)變量引用的對象布讹。

四種引用類型:

強引用:代碼中普遍存在的科侈,只要強引用還存在,垃圾收集器就不會回收掉被引用的對象炒事。
軟引用:SoftReference臀栈,用來描述還有用但是非必須的對象,當內(nèi)存不足的時候會回收這類對象挠乳。
弱引用:WeakReference权薯,用來描述非必須對象,弱引用的對象只能生存到下一次GC發(fā)生時睡扬,當GC發(fā)生時盟蚣,無論內(nèi)存是否足夠,都會回收該對象卖怜。
虛引用:PhantomReference屎开,一個對象是否有虛引用的存在,完全不會對其生存時間產(chǎn)生影響马靠,也無法通過虛引用取得一個對象的引用屿脐,它存在的唯一目的是在這個對象被回收時可以收到一個系統(tǒng)通知蛔琅。

虛引用必須與 ReferenceQueue 一起使用,當 GC 準備回收一個對象,如果發(fā)現(xiàn)它有虛引用扰她,就會在回收之前工闺,把這個 虛引用 加入到與之關(guān)聯(lián)的 ReferenceQueue 中袍患。
leakcanary利用這個原理音诫,我們可以檢測到對象何時被回收

回收算法:

1).標記-清除(Mark-sweep)

標記-清除算法采用從根集合進行掃描,對存活的對象進行標記揖赴,標記完畢后馆匿,再掃描整個空間中未被標記的對象,進行回收燥滑。標記-清除算法不需要進行對象的移動渐北,并且僅對不存活的對象進行處理,在存活對象比較多的情況下極為高效突倍,但由于標記-清除算法直接回收不存活的對象腔稀,因此會造成內(nèi)存碎片盆昙。

2).標記-整理(Mark-Compact)

標記-整理算法采用標記-清除算法一樣的方式進行對象的標記羽历,但在清除時不同焊虏,在回收不存活的對象占用的空間后,會將所有的存活對象往左端空閑空間移動秕磷,并更新對應的指針诵闭。標記-整理算法是在標記-清除算法的基礎(chǔ)上,又進行了對象的移動澎嚣,因此成本更高疏尿,但是卻解決了內(nèi)存碎片的問題易桃。該垃圾回收算法適用于對象存活率高的場景(老年代)。

3).復制(Copying)

復制算法將可用內(nèi)存按容量劃分為大小相等的兩塊晤郑,每次只使用其中的一塊。當這一塊的內(nèi)存用完了造寝,就將還存活著的對象復制到另外一塊上面磕洪,然后再把已使用過的內(nèi)存空間一次清理掉诫龙。這種算法適用于對象存活率低的場景,比如新生代签赃。這樣使得每次都是對整個半?yún)^(qū)進行內(nèi)存回收谷异,內(nèi)存分配時也就不用考慮內(nèi)存碎片等復雜情況。

4).分代收集算法

不同的對象的生命周期(存活情況)是不一樣的锦聊,而不同生命周期的對象位于堆中不同的區(qū)域,因此對堆內(nèi)存不同區(qū)域采用不同的策略進行回收可以提高 JVM 的執(zhí)行效率荞下。當代商用虛擬機使用的都是分代收集算法:新生代對象存活率低史飞,就采用復制算法;老年代存活率高抽诉,就用標記清除算法或者標記整理算法。Java堆內(nèi)存一般可以分為新生代迹淌、老年代和永久代三個模塊:

類的加載

類的生命周期:1.加載;2.驗證耙饰;3.準備纹份;4.解析;5.初始化件已;6.使用元暴;7.卸載
系統(tǒng)加載 Class 類型的文件主要三步:加載->連接->初始化。連接過程又可分為三步:驗證->準備->解析鉴未。
類加載過程:1.加載:獲取類的二進制字節(jié)流援岩;生成方法區(qū)的運行時存儲結(jié)構(gòu);在內(nèi)存中生成 Class 對象 2.驗證:確保該 Class 字節(jié)流符合虛擬機要求 3.準備:為類變量分配內(nèi)存羽峰,初始化靜態(tài)變量 4.解析:將常量池的符號引用替換為直接引用 5.初始化:執(zhí)行靜態(tài)塊代碼添瓷、類變量賦值

解析舉個例子:在程序執(zhí)行方法時,系統(tǒng)需要明確知道這個方法所在的位置坯汤。Java 虛擬機為每個類都準備了一張方法表來存放類中所有的方法搀愧。當需要調(diào)用一個類的方法的時候,只要知道這個方法在方法表中的偏移量就可以直接調(diào)用該方法了咱筛。通過解析操作符號引用就可以直接轉(zhuǎn)變?yōu)槟繕朔椒ㄔ陬愔蟹椒ū淼奈恢醚嘎幔瑥亩沟梅椒梢员徽{(diào)用。

裝飾者模式vs代理模式

裝飾者模式

第一代機器人只會跳舞饲趋,第二代機器人通過傳入第一代機器人擁有了跳舞功能,然后增加唱歌功能呢堂污。
public interface Robot {
   void dance();
}
public class  firstRobot implements Robot {
 
   @Override
   public void dance() {
      System.out.println("dance: dance");
   }
}
public class twoRobot implements Robot {
   protected Robot rebot;
 
   public ShapeDecorator(Robot rebot){
      this.rebot = rebot;
   }
 
   public void dance(){
      rebot.dance();
   }  
  public void singing(){

  }
}

代理模式

public interface Image {
   void display();
}
public class RealImage implements Image {
 
   private String fileName;
 
   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }
 
   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }
 
   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}
public class ProxyImage implements Image{
 
   private RealImage realImage;
   private String fileName;
 
   public ProxyImage(String fileName){
      this.fileName = fileName;
   }
 
   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}
public class ProxyPatternDemo {
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");
      // 圖像將從磁盤加載
      image.display(); 
      System.out.println("");
      // 圖像不需要從磁盤加載
      image.display();  
   }
}
兩個模式的區(qū)別

讓別人幫助你做你并不關(guān)心的事情敷鸦,叫代理模式
為讓自己的能力增強寝贡,使得增強后的自己能夠使用更多的方法,拓展在自己基礎(chǔ)之上的功能的碟案,叫裝飾器模式

hashmap

長度16或者其他2的冪颇蜡,Length-1的值是所有二進制位全為1,這種情況下鳖目,index的結(jié)果等同于HashCode后幾位的值缤弦。只要輸入的HashCode本身分布均勻,Hash算法的結(jié)果就是均勻的狸捅。

hash沖突的解決

1.鏈式尋址法累提,這是一種常見的方法,簡單理解就是把存在Hash沖突的key朽褪,以單向鏈表來進行存儲
2.開放定址法也稱線性探測法无虚,就是從發(fā)生沖突的那個位置開始,按照一定次序從Hash表找到一個空閑位置然后把發(fā)生沖突的元素存入到這個位置橡淑,而在java中咆爽,ThreadLocal就用到了線性探測法來解決Hash沖突
3.再Hash法置森,就是通過某個Hash函數(shù)計算的key符糊,存在沖突的時候,再用另外一個Hash函數(shù)對這個可以進行Hash行贪,一直運算模闲,直到不再產(chǎn)生沖突為止,這種方式會增加計算的一個時間,性能上呢會有一些影響
4.建立公共移除區(qū)啰脚,就是把Hash表分為基本表和益處表兩個部分实夹,凡是存在沖突的元素,一律放到益處表中

hashmap的擴容機制
 1荸实、默認的初始化容量大小為16缴淋,必須為 2 的冪次方
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
 
 2、最大的容量圆存,在兩個帶參數(shù)的構(gòu)造函數(shù)隱式指定更高值時使用仇哆,必須為 2的冪次方
    static final int MAXIMUM_CAPACITY = 1 << 30;
 
 3、默認的負載因數(shù)油讯,這個值最好不要改動延欠,這個值可以大于1.
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
   
 4由捎、鏈表轉(zhuǎn)紅黑樹的閾值:
    static final int TREEIFY_THRESHOLD = 8;
    
 5、紅黑樹退化成鏈表的閾值:
    static final int UNTREEIFY_THRESHOLD = 6;
    
 6、當哈希表的容量大于64時涧窒,才允許樹化(鏈表轉(zhuǎn)紅黑樹)锭亏,如果小于64,則直接擴容戴已,這個值不能小于4*TREEIFY_THRESHOLD锅减。不然會進行選擇擴容還是樹化。
     static final int MIN_TREEIFY_CAPACITY = 64;

2.1 什么時候發(fā)生擴容
在jdk1.8中休玩,當元素數(shù)量超過閾值(容量*負載因子)時,一般就會發(fā)生擴容独泞,每次擴容的容量都是之前容量的2 倍數(shù)懦砂。
HashMap的容量是有上限的荞膘,必須小于1<<30羽资。如果容量超出了這個數(shù),則不再增長狭郑,且閾值會被設(shè)置為Integer.MAX_VALUE脏答。
(1)就是hashmap在存值的時候(默認大小為16,負載因子0.75糙麦,閾值12)丛肮,可能達到最后存滿16個值的時候,再存入第17個值才會發(fā)生擴容現(xiàn)象焚廊,因為前16個值习劫,每個值在底層數(shù)組中分別占據(jù)一個位置,并沒有發(fā)生hash碰撞袒餐。

(2)當然也有可能存儲更多值(超多16個值谤狡,最多可以存26個值)都還沒有擴容。原理:前11個值全部hash碰撞焰宣,存到數(shù)組的同一個位置(雖然hash沖突捕仔,但是這時元素個數(shù)小于閾值12,并沒有同時滿足擴容的兩個條件闪唆。所以不會擴容)钓葫,后面所有存入的15個值全部分散到數(shù)組剩下的15個位置(這時元素個數(shù)大于等于閾值瓤逼,但是每次存入的元素并沒有發(fā)生hash碰撞,也沒有同時滿足擴容的兩個條件贷帮,所以葉不會擴容)诱告,前面11+15=26,所以在存入第27個值的時候才同時滿足上面兩個條件锄禽,這時候才會發(fā)生擴容現(xiàn)象。

在1.8版本中是先插入再擴容(除非第一次初始化是先初始化再插入值)磁滚,所以在1.8中key的個數(shù)大于閾值便會擴容宵晚。

activity的啟動流程

launcher進程通過binder傳入上下文包名信息-->systemserver進程收到包名信息-->通過socket通知zygote進程——》fork一個app進程——》app進程通過binder進程發(fā)送attachApplication的信息---->systemserver進程AMS通過activity的代理類通過binder送scheduleLaunchActivity請求————》app進程的activityThreader通過handler發(fā)送啟動Launcher_activity

activity的渲染流程

onresume執(zhí)行之后淤刃,會開始進行Activity的繪制,將Activity的dectorView attach 到window上陨仅,此后開始界面的渲染繪制铝侵。

因此哟沫,根據(jù)我們一般的開發(fā)習慣,在oncreate中執(zhí)行setContentView,調(diào)用了xml的inflate方法孔祸,并不意味著布局文件已經(jīng)渲染完畢崔慧,LayoutInflater 進行 inflate的過程,僅僅是將布局文件中定義的 view 元素通過調(diào)用createViewFromTag方法實例化的過程悼泌。setContentView實現(xiàn)了布局文件到j(luò)ava對象的轉(zhuǎn)換,卻并沒有開始渲染和繪制丙者。view的繪制發(fā)生在activity attachToWindow之后评汰,執(zhí)行WindowManagerImpl的addView方法

線程池的傳參
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    //...
}
corePoolSize:核心線程數(shù)兰绣,線程池正常情況下保持的線程數(shù)踪央,大戶人家“長工”的數(shù)量畅蹂。
maximumPoolSize:最大線程數(shù)累贤,當線程池繁忙時最多可以擁有的線程數(shù),大戶人家“長工”+“短工”的總數(shù)量渗磅。
keepAliveTime:空閑線程存活時間脆贵,沒有活之后“短工”可以生存的最大時間状勤。
TimeUnit:時間單位密似,配合參數(shù) 3 一起使用残腌,用于描述參數(shù) 3 的時間單位闺金。
BlockingQueue:線程池的任務隊列,用于保存線程池待執(zhí)行任務的容器。
ThreadFactory:線程工廠欢顷,用于創(chuàng)建線程池中線程的工廠方法炼七,通過它可以設(shè)置線程的命名規(guī)則特石、優(yōu)先級和線程類型芙委。
RejectedExecutionHandler:拒絕策略,當任務量超過線程池可以保存的最大任務數(shù)時侧啼,執(zhí)行的策略。
參數(shù)7:RejectedExecutionHandler

拒絕策略:當線程池的任務超出線程池隊列可以存儲的最大值之后蛾魄,執(zhí)行的策略叽奥。
默認的拒絕策略有以下 4 種:

AbortPolicy:拒絕并拋出異常魔市。
CallerRunsPolicy:使用當前調(diào)用的線程來執(zhí)行此任務。
DiscardOldestPolicy:拋棄隊列頭部(最舊)的一個任務磅网,并執(zhí)行當前任務。
DiscardPolicy:忽略并拋棄當前任務燎潮。
線程池的默認策略是 AbortPolicy 拒絕并拋出異常。

參數(shù)5:BlockingQueue

阻塞隊列:線程池存放任務的隊列爪喘,用來存儲線程池的所有待執(zhí)行任務稠诲。
它可以設(shè)置以下幾個值:

ArrayBlockingQueue:一個由數(shù)組結(jié)構(gòu)組成的有界阻塞隊列略水。
LinkedBlockingQueue:一個由鏈表結(jié)構(gòu)組成的有界阻塞隊列聚请。
SynchronousQueue:一個不存儲元素的阻塞隊列,即直接提交給線程不保持它們盖文。
PriorityBlockingQueue:一個支持優(yōu)先級排序的無界阻塞隊列龄恋。
DelayQueue:一個使用優(yōu)先級隊列實現(xiàn)的無界阻塞隊列郭毕,只有在延遲期滿時才能從中提取元素扳肛。
LinkedTransferQueue:一個由鏈表結(jié)構(gòu)組成的無界阻塞隊列兽肤。與SynchronousQueue類似沉迹,還含有非阻塞方法。
LinkedBlockingDeque:一個由鏈表結(jié)構(gòu)組成的雙向阻塞隊列葫松。
比較常用的是 LinkedBlockingQueue亥揖,線程池的排隊策略和 BlockingQueue 息息相關(guān)摧扇。

內(nèi)存優(yōu)化工具的使用

Android Profiler分為三大模塊: cpu、內(nèi)存 、網(wǎng)絡(luò)帮匾。

耗時的查詢:
內(nèi)存的具體分析:

Android Profiler 工具參考官方文檔 : 使用 Memory Profiler 查看 Java 堆和內(nèi)存分配
1.profiler查找內(nèi)存泄漏
內(nèi)存泄漏代碼:通過一個靜態(tài)的單例夏跷,每次關(guān)閉activity持有了MainActivity2

public class PendingOrderManager {
    private static PendingOrderManager instance;

    private Context mContext;

    public PendingOrderManager(Context context) {
        this.mContext = context;
    }

    public static PendingOrderManager getInstance(Context context) {
        if (instance == null) {
            instance = new PendingOrderManager(context);
        }
        return instance;
    }

}


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.w("TAG", "-----BActiviy onCreate---------");
        setContentView(R.layout.activity_main);
        TextView textView = findViewById(R.id.tt);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,MainActivity2.class);
                startActivity(intent);
            }
        });
    }
}

public class MainActivity2 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        PendingOrderManager.getInstance(MainActivity2.this);
        //finish();

    }
}

打開profile 的Memory,先點擊垃圾桶圖標gc回收下,然后操作寫好的內(nèi)存泄漏界面后,駝峰就是出現(xiàn)了內(nèi)存泄漏虾标。



勾選Capture heap dump然后Record,



我們是通過包名去尋找库继,那個感嘆號就是我們內(nèi)存泄漏的對象MainActivity2,點擊進去顯示Instance艺谆,下面有四個聊记,說明泄漏了四次狰右。
MAT使用定位內(nèi)存泄漏
快速定位耗時方法

方式1
檢測開始代碼處添加:
Debug.startMethodTracing();
檢測結(jié)束代碼處添加:
Debug.stopMethodTracing();
使用adb pull將生成的**.trace文件導出到電腦,然后使用Android Studio的Profiler加載盛垦。



打開 Android Device Monitor,在 DDMS 中打開 trace 文件或者直接使用 SDK 中的 TraceView:, TraceView 加載 trace 文件:



上圖介紹了 TraceView 的大致內(nèi)容:

上半部分顯示了 不同線程的執(zhí)行時間
其中不同的顏色表示不同的方法
同一個顏色越長,說明執(zhí)行時間越久皿哨,如圖中的主線程 main
空白表示這個時間段內(nèi)沒有執(zhí)行內(nèi)容
下半部分展示了不同方法的執(zhí)行時間信息鼓黔,關(guān)鍵指標有三個:
Cpu Time/Call :該方法平均占用 CPU 的時間
Real Time/Call :平均執(zhí)行時間澳化,包括切換稳吮、阻塞的時間灶似,>= Cpu Time
Calls + Recur Calls/Total :調(diào)用、遞歸次數(shù)
點擊下面的任意一個方法希痴,可以看到它的詳細信息:

Parents:選中方法的調(diào)用處
Children:選中方法調(diào)用的方法

方式2
打開Profiler -> CPU -> 點擊 Record -> 點擊 Stop -> 查看Profiler下方Top Down/Bottom Up 區(qū)域找出耗時的熱點方法春感。
Profile CPU
1鲫懒、Trace types
Trace Java Methods
會記錄每個方法的時間、CPU信息甲献。對運行時性能影響較大谦秧。
Sample Java Methods
相比于Trace Java Methods會記錄每個方法的時間、CPU信息锥累,它會在應用的Java代碼執(zhí)行期間頻繁捕獲應用的調(diào)用堆棧惶翻,對運行時性能的影響比較小,能夠記錄更大的數(shù)據(jù)區(qū)域议泵。
Sample C/C++ Functions
需部署到Android 8.0及以上設(shè)備缎讼,內(nèi)部使用simpleperf跟蹤應用的native代碼咽瓷,也可以命令行使用simpleperf锄开。

Trace System Calls

檢查應用與系統(tǒng)資源的交互情況袜香。查看所有核心的CPU瓶。內(nèi)部采用systrace猜敢,也可以使用systrace命令。

Android 音視屏基礎(chǔ)

在Android中,我們有三種方式來實現(xiàn)視頻的播放:
1该押、使用其自帶的播放器朝聋。指定Action為ACTION_VIEW,Data為Uri应媚,Type為其MIME類型携龟。
2、使用VideoView來播放子漩。在布局文件中使用VideoView結(jié)合MediaController來實現(xiàn)對其控制。
3花椭、使用MediaPlayer類和SurfaceView來實現(xiàn),這種方式很靈活。

SurfaceView和TextureView

SurfaceView優(yōu)點:
可以在一個獨立的線程中進行繪制顶燕,不會影響主線程
使用雙緩沖機制,播放視頻時畫面更流暢
SurfaceView缺點:
雖然繼承自view,但是view的很多屬性是用不了的,Surface不在View hierachy中久橙,它的顯示也不受View的屬性控制,所以不能進行平移,縮放等變換,也不能放在其它ViewGroup中块蚌。SurfaceView 不能嵌套使用

SurfaceView 的核心在于提供了兩個線程:UI線程和渲染線程辆毡,兩個線程通過“雙緩沖”機制來達到高效的界面刷新效果闹获。
不用畫布底扳,直接在窗口上進行繪圖叫做無緩沖繪圖若皱。用了一個畫布走触,將所有內(nèi)容都先畫到畫布上,在整體繪制到窗口上蛔添,就該叫做單緩沖繪圖兜辞,那個畫布就是一個緩沖區(qū)逸吵。用了兩個畫布缝裁,一個進行臨時的繪圖,一個進行最終的繪圖韩脑,這樣就叫做雙緩沖粹污。
而這個雙緩沖可以理解為壮吩,SurfaceView 在更新視圖時用到了兩張 Canvas:
frontCanvas:實際顯示的canvas加缘。
backCanvas:存儲的是上一次更改前的canvas觉啊。
當使用 lockCanvas() 獲取畫布時杠人,得到的實際上是 backCanvas 而不是正在顯示的 frontCanvas,之后你在獲取到的 backCanvas 上繪制新視圖辑莫,再 unlockCanvasAndPost(canvas)此視圖滤奈,那么上傳的這張 canvas 將替換原來的 frontCanvas 作為新的 frontCanvas蜒程,原來的 frontCanvas 將切換到后臺作為 backCanvas绅你。

指標 SurfaceView TextureView
內(nèi)存
繪制 及時 1-3幀的延遲
耗電
動畫和截圖 不支持 支持
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市昭躺,隨后出現(xiàn)的幾起案子忌锯,更是在濱河造成了極大的恐慌,老刑警劉巖领炫,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件偶垮,死亡現(xiàn)場離奇詭異,居然都是意外死亡帝洪,警方通過查閱死者的電腦和手機似舵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門葱峡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來砚哗,“玉大人,你說我怎么就攤上這事砰奕≈虢妫” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵军援,是天一觀的道長仅淑。 經(jīng)常有香客問我,道長胸哥,這世上最難降的妖魔是什么涯竟? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上昆禽,老公的妹妹穿的比我還像新娘蝗蛙。我一直安慰自己,他們只是感情好醉鳖,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布捡硅。 她就那樣靜靜地躺著,像睡著了一般盗棵。 火紅的嫁衣襯著肌膚如雪壮韭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天纹因,我揣著相機與錄音喷屋,去河邊找鬼。 笑死瞭恰,一個胖子當著我的面吹牛屯曹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惊畏,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼恶耽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了颜启?” 一聲冷哼從身側(cè)響起偷俭,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缰盏,沒想到半個月后涌萤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡口猜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年负溪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片济炎。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡笙以,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冻辩,到底是詐尸還是另有隱情,我是刑警寧澤拆祈,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布恨闪,位于F島的核電站,受9級特大地震影響放坏,放射性物質(zhì)發(fā)生泄漏咙咽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一淤年、第九天 我趴在偏房一處隱蔽的房頂上張望钧敞。 院中可真熱鬧蜡豹,春花似錦、人聲如沸溉苛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愚战。三九已至娇唯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寂玲,已是汗流浹背塔插。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拓哟,地道東北人想许。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像断序,于是被迫代替她去往敵國和親流纹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

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