久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁技術(shù)文章
文章詳情頁

Java 中的 Unsafe 魔法類的作用大全

瀏覽:51日期:2022-08-09 17:31:39

Unsafe是位于sun.misc包下的一個類,主要提供一些用于執(zhí)行低級別、不安全操作的方法,如直接訪問系統(tǒng)內(nèi)存資源、自主管理內(nèi)存資源等,這些方法在提升Java運行效率、增強Java語言底層資源操作能力方面起到了很大的作用。

但是,這個類的作者不希望我們使用它,因為我們雖然我們獲取到了對底層的控制權(quán),但是也增大了風(fēng)險,安全性正是Java相對于C++/C的優(yōu)勢。因為該類在sun.misc包下,默認(rèn)是被BootstrapClassLoader加載的。如果我們在程序中去調(diào)用這個類的話,我們使用的類加載器肯定是 AppClassLoader,問題是在Unsafe中是這樣寫的:

private static final Unsafe theUnsafe;private Unsafe() {}@CallerSensitivepublic static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException('Unsafe'); } else { return theUnsafe; }}

將構(gòu)造函數(shù)私有,然后提供了一個靜態(tài)方法去獲取當(dāng)前類實例。在getUnsafe()方法中首先判斷當(dāng)前類加載器是否為空,因為使用 BootstrapClassLoader 本身就是空,它是用c++實現(xiàn)的,這樣就限制了我們在自己的代碼中使用這個類。

但是同時作者也算是給我們提供了一個后門,因為Java有反射機制。調(diào)用的思路就是將theUnsafe對象設(shè)置為可見。

Field theUnsafeField = Unsafe.class.getDeclaredField('theUnsafe');theUnsafeField.setAccessible(true);Unsafe unsafe = (Unsafe) theUnsafeField.get(null);System.out.println(unsafe);

unsafe類功能介紹:

內(nèi)存操作

這部分主要包含堆外內(nèi)存的分配、拷貝、釋放、給定地址值操作等方法。

//分配內(nèi)存, 相當(dāng)于C++的malloc函數(shù)public native long allocateMemory(long bytes);//擴(kuò)充內(nèi)存public native long reallocateMemory(long address, long bytes);//釋放內(nèi)存public native void freeMemory(long address);//在給定的內(nèi)存塊中設(shè)置值public native void setMemory(Object o, long offset, long bytes, byte value);//內(nèi)存拷貝public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);//獲取給定地址值,忽略修飾限定符的訪問限制。與此類似操作還有: getInt,getDouble,getLong,getChar等public native Object getObject(Object o, long offset);//為給定地址設(shè)置值,忽略修飾限定符的訪問限制,與此類似操作還有: putInt,putDouble,putLong,putChar等public native void putObject(Object o, long offset, Object x);//獲取給定地址的byte類型的值(當(dāng)且僅當(dāng)該內(nèi)存地址為allocateMemory分配時,此方法結(jié)果為確定的)public native byte getByte(long address);//為給定地址設(shè)置byte類型的值(當(dāng)且僅當(dāng)該內(nèi)存地址為allocateMemory分配時,此方法結(jié)果才是確定的)public native void putByte(long address, byte x);

通常,我們在Java中創(chuàng)建的對象都處于堆內(nèi)內(nèi)存(heap)中,堆內(nèi)內(nèi)存是由JVM所管控的Java進(jìn)程內(nèi)存,并且它們遵循JVM的內(nèi)存管理機制,JVM會采用垃圾回收機制統(tǒng)一管理堆內(nèi)存。與之相對的是堆外內(nèi)存,存在于JVM管控之外的內(nèi)存區(qū)域,Java中對堆外內(nèi)存的操作,依賴于Unsafe提供的操作堆外內(nèi)存的native方法。

使用堆外內(nèi)存的原因 對垃圾回收停頓的改善。由于堆外內(nèi)存是直接受操作系統(tǒng)管理而不是JVM,所以當(dāng)我們使用堆外內(nèi)存時,即可保持較小的堆內(nèi)內(nèi)存規(guī)模。從而在GC時減少回收停頓對于應(yīng)用的影響。 提升程序I/O操作的性能。通常在I/O通信過程中,會存在堆內(nèi)內(nèi)存到堆外內(nèi)存的數(shù)據(jù)拷貝操作,對于需要頻繁進(jìn)行內(nèi)存間數(shù)據(jù)拷貝且生命周期較短的暫存數(shù)據(jù),都建議存儲到堆外內(nèi)存。典型應(yīng)用

DirectByteBuffer是Java用于實現(xiàn)堆外內(nèi)存的一個重要類,通常用在通信過程中做緩沖池,如在Netty、MINA等NIO框架中應(yīng)用廣泛。DirectByteBuffer對于堆外內(nèi)存的創(chuàng)建、使用、銷毀等邏輯均由Unsafe提供的堆外內(nèi)存API來實現(xiàn)。

下面的代碼為DirectByteBuffer構(gòu)造函數(shù),創(chuàng)建DirectByteBuffer的時候,通過Unsafe.allocateMemory分配內(nèi)存、Unsafe.setMemory進(jìn)行內(nèi)存初始化,而后構(gòu)建Cleaner對象用于跟蹤DirectByteBuffer對象的垃圾回收,以實現(xiàn)當(dāng)DirectByteBuffer被垃圾回收時,分配的堆外內(nèi)存一起被釋放。

DirectByteBuffer(int cap) { // package-private super(-1, 0, cap, cap); boolean pa = VM.isDirectMemoryPageAligned(); int ps = Bits.pageSize(); long size = Math.max(1L, (long)cap + (pa ? ps : 0)); Bits.reserveMemory(size, cap); long base = 0; try { //分配內(nèi)存,返回基地址 base = unsafe.allocateMemory(size); } catch (OutOfMemoryError x) { Bits.unreserveMemory(size, cap); throw x; } //內(nèi)存初始化 unsafe.setMemory(base, size, (byte) 0); if (pa && (base % ps != 0)) { // Round up to page boundary address = base + ps - (base & (ps - 1)); } else { address = base; } //跟蹤directbytebuffer 對象的垃圾回收,實現(xiàn)堆外內(nèi)存的釋放 cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); att = null;}

上面最后一句代碼通過Cleaner.create()來進(jìn)行對象監(jiān)控,釋放堆外內(nèi)存。這里是如何做到的呢?跟蹤一下Cleaner類:

public class Cleaner extends PhantomReference<Object> { public static Cleaner create(Object var0, Runnable var1) {return var1 == null ? null : add(new Cleaner(var0, var1)); }}

可以看到繼承了PhantomReference,Java中的4大引用類型我們都知道。PhantomReference的作用于其他的Refenrence作用大有不同。像 SoftReference、WeakReference都是為了保證引用的類對象能在不用的時候及時的被回收,但是 PhantomReference 并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,對象不可達(dá)時就會被垃圾回收器回收,但是任何時候都無法通過虛引用獲得對象。虛引用主要用來跟蹤對象被垃圾回收器回收的活動。

那他的作用到底是啥呢?準(zhǔn)確來說 PhantomReference 給使用者提供了一種機制-來監(jiān)控對象的垃圾回收的活動。

可能這樣說不是太明白,我來舉個例子:

package com.rickiyang.learn.javaagent;import java.lang.ref.PhantomReference;import java.lang.ref.Reference;import java.lang.ref.ReferenceQueue;import java.lang.reflect.Field;/** * @author rickiyang * @date 2019-08-08 * @Desc */public class TestPhantomReference { public static boolean isRun = true; public static void main(String[] args) throws Exception { String str = new String('123'); System.out.println(str.getClass() + '@' + str.hashCode()); final ReferenceQueue<String> referenceQueue = new ReferenceQueue<>(); new Thread(() -> { while (isRun) {Object obj = referenceQueue.poll();if (obj != null) { try { Field rereferent = Reference.class.getDeclaredField('referent'); rereferent.setAccessible(true); Object result = rereferent.get(obj); System.out.println('gc will collect:' + result.getClass() + '@' + result.hashCode() + 't' + result); } catch (Exception e) { e.printStackTrace(); }} } }).start(); PhantomReference<String> weakRef = new PhantomReference<>(str, referenceQueue); str = null; Thread.currentThread().sleep(2000); System.gc(); Thread.currentThread().sleep(2000); isRun = false; }}

上面這段代碼的含義是new PhantomReference(),因為PhantomReference必須的維護(hù)一個ReferenceQueue用來保存當(dāng)前被虛引用的對象。上例中手動去調(diào)用referenceQueue.poll()方法,這里你需要注意的是并不是我們主動去釋放queue中的對象,你跟蹤進(jìn)去 poll() 方法可以看到有一個全局鎖對象,只有當(dāng)當(dāng)前對象失去了引用之后才會釋放鎖,poll()方法才能執(zhí)行。在執(zhí)行poll()方法釋放對象的時候我們可以針對這個對象做一些監(jiān)控。這就是 PhantomReference 的意義所在。

說回到 Cleaner, 通過看源碼,create()方法調(diào)用了add()方法,在Cleaner類里面維護(hù)了一個雙向鏈表,將每一個add進(jìn)來的Cleaner對象都添加到這個鏈表中維護(hù)。那么在Cleaner 鏈表中的對象實在何時被釋放掉呢?

注意到 Cleaner中有一個clean()方法:

public void clean() { if (remove(this)) { try { this.thunk.run(); } catch (final Throwable var2) { AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() { if (System.err != null) { (new Error('Cleaner terminated abnormally', var2)).printStackTrace(); } System.exit(1); return null;} }); } }}

remove()方法是將該對象從內(nèi)部維護(hù)的雙向鏈表中清除。下面緊跟著是thunk.run() ,thunk = 我們通過create()方法傳進(jìn)來的參數(shù),在``DirectByteBuffer中那就是:Cleaner.create(this, new Deallocator(base, size, cap))`,Deallocator類也是一個線程:

private static class Deallocatorimplements Runnable {private static Unsafe unsafe = Unsafe.getUnsafe(); //省略無關(guān) 代碼public void run() { if (address == 0) {// Paranoiareturn; } unsafe.freeMemory(address); address = 0; Bits.unreserveMemory(size, capacity);} }

看到在run方法中調(diào)用了freeMemory()去釋放掉對象。

在 Reference類中調(diào)用了該方法,Reference 類中的靜態(tài)代碼塊 有個一內(nèi)部類:ReferenceHandler,它繼承了 Thread,在run方法中調(diào)用了 tryHandlePending(),并且被設(shè)置為守護(hù)線程,意味著會循環(huán)不斷的處理pending鏈表中的對象引用。

這里要注意的點是:

Cleaner本身不帶有清理邏輯,所有的邏輯都封裝在thunk中,因此thunk是怎么實現(xiàn)的才是最關(guān)鍵的。

另外,Java 最新核心技術(shù)系列教程和示例源碼看這里:https://github.com/javastacks/javastack

static { ThreadGroup tg = Thread.currentThread().getThreadGroup(); for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()); Thread handler = new ReferenceHandler(tg, 'Reference Handler'); /* If there were a special system-only priority greater than * MAX_PRIORITY, it would be used here */ handler.setPriority(Thread.MAX_PRIORITY); handler.setDaemon(true); handler.start(); // provide access in SharedSecrets SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() { @Override public boolean tryHandlePendingReference() { return tryHandlePending(false); } });}static boolean tryHandlePending(boolean waitForNotify) { Reference<Object> r; Cleaner c; try { synchronized (lock) { if (pending != null) {r = pending;//如果當(dāng)前Reference對象是Cleaner類型的就進(jìn)行特殊處理c = r instanceof Cleaner ? (Cleaner) r : null;// unlink ’r’ from ’pending’ chainpending = r.discovered;r.discovered = null; } else {// The waiting on the lock may cause an OutOfMemoryError// because it may try to allocate exception objects.if (waitForNotify) { lock.wait();}// retry if waitedreturn waitForNotify; } } } catch (OutOfMemoryError x) { Thread.yield(); // retry return true; } catch (InterruptedException x) { // retry return true; } // clean 不為空的時候,走清理的邏輯 if (c != null) { c.clean(); return true; } ReferenceQueue<? super Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); return true;}

tryHandlePending這段代碼的意思是:

如果一個對象經(jīng)過JVM檢測他已經(jīng)沒有強引用了,但是還有 弱引用 或者 軟引用 或者 虛引用的情況下,那么就會把此對象放到一個名為pending的鏈表里,這個鏈表是通過Reference.discovered域連接在一起的。

ReferenceHandler這個線程會一直從鏈表中取出被pending的對象,它可能是WeakReference,也可能是SoftReference,當(dāng)然也可能是PhantomReference和Cleaner。如果是Cleaner,那就直接調(diào)用Cleaner的clean方法,然后就結(jié)束了。其他的情況下,要交給這個對象所關(guān)聯(lián)的queue,以便于后續(xù)的處理。

關(guān)于堆外內(nèi)存分配和回收的代碼我們就先分析到這里。需要注意的是對外內(nèi)存回收的時機也是不確定的,所以不要持續(xù)分配一些大對象到堆外,如果沒有被回收掉,這是一件很可怕的事情。畢竟它無法被JVM檢測到。

內(nèi)存屏障

硬件層的內(nèi)存屏障分為兩種:Load Barrier 和 Store Barrier即讀屏障和寫屏障。內(nèi)存屏障有兩個作用:阻止屏障兩側(cè)的指令重排序;強制把寫緩沖區(qū)/高速緩存中的臟數(shù)據(jù)等寫回主內(nèi)存,讓緩存中相應(yīng)的數(shù)據(jù)失效。在Unsafe中提供了三個方法來操作內(nèi)存屏障:

//讀屏障,禁止load操作重排序。屏障前的load操作不能被重排序到屏障后,屏障后的load操作不能被重排序到屏障前public native void loadFence();//寫屏障,禁止store操作重排序。屏障前的store操作不能被重排序到屏障后,屏障后的store操作不能被重排序到屏障前public native void storeFence();//全能屏障,禁止load、store操作重排序public native void fullFence();

先簡單了解兩個指令:

Store:將處理器緩存的數(shù)據(jù)刷新到內(nèi)存中。 Load:將內(nèi)存存儲的數(shù)據(jù)拷貝到處理器的緩存中。

JVM平臺提供了一下幾種內(nèi)存屏障:

屏障類型 指令示例 說明 LoadLoad Barriers Load1;LoadLoad;Load2 該屏障確保Load1數(shù)據(jù)的裝載先于Load2及其后所有裝載指令的的操作 StoreStore Barriers Store1;StoreStore;Store2 該屏障確保Store1立刻刷新數(shù)據(jù)到內(nèi)存(使其對其他處理器可見)該操作先于Store2及其后所有存儲指令的操作 LoadStore Barriers Load1;LoadStore;Store2 確保Load1的數(shù)據(jù)裝載先于Store2及其后所有的存儲指令刷新數(shù)據(jù)到內(nèi)存的操作 StoreLoad Barriers Store1;StoreLoad;Load2 該屏障確保Store1立刻刷新數(shù)據(jù)到內(nèi)存的操作先于Load2及其后所有裝載裝載指令的操作。它會使該屏障之前的所有內(nèi)存訪問指令(存儲指令和訪問指令)完成之后,才執(zhí)行該屏障之后的內(nèi)存訪問指令

StoreLoad Barriers同時具備其他三個屏障的效果,因此也稱之為全能屏障(mfence),是目前大多數(shù)處理器所支持的;但是相對其他屏障,該屏障的開銷相對昂貴。

loadFence

實現(xiàn)了LoadLoad Barriers,該操作禁止了指令的重排序。

storeFence

實現(xiàn)了 StoreStore Barriers,確保屏障前的寫操作能夠立刻刷入到主內(nèi)存,并且確保屏障前的寫操作一定先于屏障后的寫操作。即保證了內(nèi)存可見性和禁止指令重排序。

fullFence

實現(xiàn)了 StoreLoad Barriers,強制所有在mfence指令之前的store/load指令,都在該mfence指令執(zhí)行之前被執(zhí)行;所有在mfence指令之后的store/load指令,都在該mfence指令執(zhí)行之后被執(zhí)行。

在 JDK 中調(diào)用了 內(nèi)存屏障這幾個方法的實現(xiàn)類有 StampedLock。關(guān)于StampedLock的實現(xiàn)我們后面會專門抽出一篇去講解。它并沒有去實現(xiàn)AQS隊列。而是采用了 其他方式實現(xiàn)。

系統(tǒng)相關(guān)

這部分包含兩個獲取系統(tǒng)相關(guān)信息的方法。

//返回系統(tǒng)指針的大小。返回值為4(32位系統(tǒng))或 8(64位系統(tǒng))。public native int addressSize(); //內(nèi)存頁的大小,此值為2的冪次方。public native int pageSize();

在 java.nio下的Bits類中調(diào)用了pagesize()方法計算系統(tǒng)中頁大小:

private static int pageSize = -1;static int pageSize() { if (pageSize == -1)pageSize = unsafe().pageSize(); return pageSize;}線程調(diào)度

線程調(diào)度中提供的方法包括:線程的掛起,恢復(fù) 和 對象鎖機制等,其中獲取對象的監(jiān)視器鎖方法已經(jīng)被標(biāo)記為棄用。

// 終止掛起的線程,恢復(fù)正常.java.util.concurrent包中掛起操作都是在LockSupport類實現(xiàn)的,其底層正是使用這兩個方法public native void unpark(Object thread);// 線程調(diào)用該方法,線程將一直阻塞直到超時,或者是中斷條件出現(xiàn)。public native void park(boolean isAbsolute, long time);//獲得對象鎖(可重入鎖)@Deprecatedpublic native void monitorEnter(Object o);//釋放對象鎖@Deprecatedpublic native void monitorExit(Object o);//嘗試獲取對象鎖@Deprecatedpublic native boolean tryMonitorEnter(Object o);

將一個線程進(jìn)行掛起是通過 park 方法實現(xiàn)的,調(diào)用park()后,線程將一直 阻塞 直到 超時 或者 中斷 等條件出現(xiàn)。unpark可以釋放一個被掛起的線程,使其恢復(fù)正常。整個并發(fā)框架中對線程的掛起操作被封裝在LockSupport類中,LockSupport 類中有各種版本 pack 方法,但最終都調(diào)用了Unsafe.park()方法。 我們來看一個例子:

package leetcode;import sun.misc.Unsafe;import java.lang.reflect.Field;import java.util.concurrent.TimeUnit;/** * @author: rickiyang * @date: 2019/8/10 * @description: */public class TestUsafe { private static Thread mainThread; public Unsafe getUnsafe() throws Exception {Field theUnsafeField = Unsafe.class.getDeclaredField('theUnsafe');theUnsafeField.setAccessible(true);return (Unsafe) theUnsafeField.get(null); } public void testPark() throws Exception {Unsafe unsafe = getUnsafe();mainThread = Thread.currentThread();System.out.println(String.format('park %s', mainThread.getName()));unsafe.park(false, TimeUnit.SECONDS.toNanos(3));new Thread(() -> { System.out.println(String.format('%s unpark %s', Thread.currentThread().getName(), mainThread.getName())); unsafe.unpark(mainThread);}).start();System.out.println('main thread is done'); } public static void main(String[] args) throws Exception {TestUsafe testUsafe = new TestUsafe();testUsafe.testPark(); }}

運行上面的例子,那你會發(fā)現(xiàn)在第29行 park方法設(shè)置了超時時間為3秒后,會阻塞當(dāng)前主線程,直到超時時間到達(dá),下面的代碼才會繼續(xù)執(zhí)行。

對象操作

Unsafe類中提供了多個方法來進(jìn)行 對象實例化 和 獲取對象的偏移地址 的操作:

// 傳入一個Class對象并創(chuàng)建該實例對象,但不會調(diào)用構(gòu)造方法public native Object allocateInstance(Class<?> cls) throws InstantiationException;// 獲取字段f在實例對象中的偏移量public native long objectFieldOffset(Field f);// 返回值就是f.getDeclaringClass()public native Object staticFieldBase(Field f);// 靜態(tài)屬性的偏移量,用于在對應(yīng)的Class對象中讀寫靜態(tài)屬性public native long staticFieldOffset(Field f);// 獲得給定對象偏移量上的int值,所謂的偏移量可以簡單理解為指針指向該變量;的內(nèi)存地址,// 通過偏移量便可得到該對象的變量,進(jìn)行各種操作public native int getInt(Object o, long offset);// 設(shè)置給定對象上偏移量的int值public native void putInt(Object o, long offset, int x);// 獲得給定對象偏移量上的引用類型的值public native Object getObject(Object o, long offset);// 設(shè)置給定對象偏移量上的引用類型的值public native void putObject(Object o, long offset, Object x););// 設(shè)置給定對象的int值,使用volatile語義,即設(shè)置后立馬更新到內(nèi)存對其他線程可見public native void putIntVolatile(Object o, long offset, int x);// 獲得給定對象的指定偏移量offset的int值,使用volatile語義,總能獲取到最新的int值。public native int getIntVolatile(Object o, long offset);// 與putIntVolatile一樣,但要求被操作字段必須有volatile修飾public native void putOrderedInt(Object o, long offset, int x);

allocateInstance方法在這幾個場景下很有用:跳過對象的實例化階段(通過構(gòu)造函數(shù))、忽略構(gòu)造函數(shù)的安全檢查(反射newInstance()時)、你需要某類的實例但該類沒有public的構(gòu)造函數(shù)。

另外,Java 最新核心技術(shù)系列教程和示例源碼看這里:https://github.com/javastacks/javastack

舉個例子:

public class User { private String name; private int age; private static String address = 'beijing'; public User(){name = 'xiaoming'; } public String getname(){return name; }}/** * 實例化對象 * @throws Exception */public void newInstance() throws Exception{ TestUsafe testUsafe = new TestUsafe(); Unsafe unsafe = testUsafe.getUnsafe(); User user = new User(); System.out.println(user.getname()); User user1 = User.class.newInstance(); System.out.println(user1.getname()); User o = (User)unsafe.allocateInstance(User.class); System.out.println(o.getname());}

打印的結(jié)果可以看到最后輸出的是null,說明構(gòu)造函數(shù)未被加載。可以進(jìn)一步實驗,將User類中的構(gòu)造函數(shù)設(shè)置為 private,你會發(fā)現(xiàn)在前面兩種實例化方式檢查期就報錯。但是第三種是可以用的。這是因為allocateInstance只是給對象分配了內(nèi)存,它并不會初始化對象中的屬性。

下面是對象操作的使用示例:

public void testObject() throws Exception{ TestUsafe testUsafe = new TestUsafe(); Unsafe unsafe = testUsafe.getUnsafe(); //通過allocateInstance創(chuàng)建對象,為其分配內(nèi)存地址,不會加載構(gòu)造函數(shù) User user = (User) unsafe.allocateInstance(User.class); System.out.println(user); // Class && Field Class<? extends User> userClass = user.getClass(); Field name = userClass.getDeclaredField('name'); Field age = userClass.getDeclaredField('age'); Field location = userClass.getDeclaredField('address'); // 獲取實例域name和age在對象內(nèi)存中的偏移量并設(shè)置值 System.out.println(unsafe.objectFieldOffset(name)); unsafe.putObject(user, unsafe.objectFieldOffset(name), 'xiaoming'); System.out.println(unsafe.objectFieldOffset(age)); unsafe.putInt(user, unsafe.objectFieldOffset(age), 18); System.out.println(user); // 獲取定義location字段的類 Object staticFieldBase = unsafe.staticFieldBase(location); System.out.println(staticFieldBase); // 獲取static變量address的偏移量 long staticFieldOffset = unsafe.staticFieldOffset(location); // 獲取static變量address的值 System.out.println(unsafe.getObject(staticFieldBase, staticFieldOffset)); // 設(shè)置static變量address的值 unsafe.putObject(staticFieldBase, staticFieldOffset, 'tianjin'); System.out.println(user + ' ' + user.getAddress());}對象實例布局與內(nèi)存大小

一個Java對象占用多大的內(nèi)存空間呢?這個問題很值得讀者朋友去查一下。 因為這個輸出本篇的重點所以簡單說一下。一個 Java 對象在內(nèi)存中由對象頭、示例數(shù)據(jù)和對齊填充構(gòu)成。對象頭存儲了對象運行時的基本數(shù)據(jù),如 hashCode、鎖狀態(tài)、GC 分代年齡、類型指針等等。實例數(shù)據(jù)是對象中的非靜態(tài)字段值,可能是一個原始類型的值,也可能是一個指向其他對象的指針。對齊填充就是 padding,保證對象都采用 8 字節(jié)對齊。除此以外,在 64 位虛擬機中還可能會開啟指針壓縮,將 8 字節(jié)的指針壓縮為 4 字節(jié),這里就不再過多介紹了。

也就是說一個 Java 對象在內(nèi)存中,首先是對象頭,然后是各個類中字段的排列,這之間可能會有 padding 填充。這樣我們大概就能理解字段偏移量的含義了,它實際就是每個字段在內(nèi)存中所處的位置。

public class User { private String name; private int age;}TestUsafe testUsafe = new TestUsafe();Unsafe unsafe = testUsafe.getUnsafe();for (Field field : User.class.getDeclaredFields()) { System.out.println(field.getName() + '-' + field.getType() + ': ' + unsafe.objectFieldOffset(field));}結(jié)果:name-class java.lang.String: 16age-int: 12

從上面的運行結(jié)果中可以:age:偏移值為12,即前面 12 個字節(jié)的對象頭;

name:name從16字節(jié)開始,因為int 類型的age占了4個字節(jié)。

繼續(xù)算下去整個對象占用的空間,對象頭12,age 4,name 是指針類型,開啟指針壓縮占用4個字節(jié),那么User對象整個占用20字節(jié),因為上面說的padding填充,必須8字節(jié)對齊,那么實際上會補上4個字節(jié)的填充,即一共占用了24個字節(jié)。

按照這種計算方式,我們可以字節(jié)寫一個計算size的工具類:

public static long sizeOf(Object o) throws Exception{ TestUsafe testUsafe = new TestUsafe(); Unsafe unsafe = testUsafe.getUnsafe(); HashSet<Field> fields = new HashSet<Field>(); Class c = o.getClass(); while (c != Object.class) {for (Field f : c.getDeclaredFields()) { if ((f.getModifiers() & Modifier.STATIC) == 0) {fields.add(f); }}//如果有繼承父類的話,父類中的屬性也是要計算的c = c.getSuperclass(); } //計算每個字段的偏移量,因為第一個字段的偏移量即在對象頭的基礎(chǔ)上偏移的 //所以只需要比較當(dāng)前偏移量最大的字段即表示這是該對象最后一個字段的位置 long maxSize = 0; for (Field f : fields) {long offset = unsafe.objectFieldOffset(f);if (offset > maxSize) { maxSize = offset;} } //上面計算的是對象最后一個字段的偏移量起始位置,java中對象最大長度是8個字節(jié)(long) //這里的計算方式是 將 當(dāng)前偏移量 / 8 + 8字節(jié) 的padding return ((maxSize/8) + 1) * 8;}

上面的工具類計算的結(jié)果也是24。

class相關(guān)操作

//靜態(tài)屬性的偏移量,用于在對應(yīng)的Class對象中讀寫靜態(tài)屬性public native long staticFieldOffset(Field f);//獲取一個靜態(tài)字段的對象指針public native Object staticFieldBase(Field f);//判斷是否需要初始化一個類,通常在獲取一個類的靜態(tài)屬性的時候(因為一個類如果沒初始化,它的靜態(tài)屬性也不會初始化)使用。 當(dāng)且僅當(dāng)ensureClassInitialized方法不生效時返回falsepublic native boolean shouldBeInitialized(Class<?> c);//確保類被初始化public native void ensureClassInitialized(Class<?> c);//定義一個類,可用于動態(tài)創(chuàng)建類,此方法會跳過JVM的所有安全檢查,默認(rèn)情況下,ClassLoader(類加載器)和ProtectionDomain(保護(hù)域)實例來源于調(diào)用者public native Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain);//定義一個匿名類,可用于動態(tài)創(chuàng)建類public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);數(shù)組操作

數(shù)組操作主要有兩個方法:

//返回數(shù)組中第一個元素的偏移地址public native int arrayBaseOffset(Class<?> arrayClass);//返回數(shù)組中一個元素占用的大小public native int arrayIndexScale(Class<?> arrayClass);CAS操作

相信所有的開發(fā)者對這個詞都不陌生,在AQS類中使用了無鎖的方式來進(jìn)行并發(fā)控制,主要就是CAS的功勞。

CAS的全稱是Compare And Swap 即比較交換,其算法核心思想如下

執(zhí)行函數(shù):CAS(V,E,N)

包含3個參數(shù)

V表示要更新的變量 E表示預(yù)期值 N表示新值

如果V值等于E值,則將V的值設(shè)為N。若V值和E值不同,則說明已經(jīng)有其他線程做了更新,則當(dāng)前線程什么都不做。通俗的理解就是CAS操作需要我們提供一個期望值,當(dāng)期望值與當(dāng)前線程的變量值相同時,說明沒有別的線程修改該值,當(dāng)前線程可以進(jìn)行修改,也就是執(zhí)行CAS操作,但如果期望值與當(dāng)前線程不符,則說明該值已被其他線程修改,此時不執(zhí)行更新操作,但可以選擇重新讀取該變量再嘗試再次修改該變量,也可以放棄操作。

Unsafe類中提供了三個方法來進(jìn)行CAS操作:

public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object update);public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update); public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);

另外,在 JDK1.8中新增了幾個 CAS 的方法,他們的實現(xiàn)是基于上面三個方法做的一層封裝:

//1.8新增,給定對象o,根據(jù)獲取內(nèi)存偏移量指向的字段,將其增加delta, //這是一個CAS操作過程,直到設(shè)置成功方能退出循環(huán),返回舊值 public final int getAndAddInt(Object o, long offset, int delta) { int v; do { //獲取內(nèi)存中最新值 v = getIntVolatile(o, offset); //通過CAS操作 } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; }//1.8新增,方法作用同上,只不過這里操作的long類型數(shù)據(jù) public final long getAndAddLong(Object o, long offset, long delta) { long v; do { v = getLongVolatile(o, offset); } while (!compareAndSwapLong(o, offset, v, v + delta)); return v; } //1.8新增,給定對象o,根據(jù)獲取內(nèi)存偏移量對于字段,將其 設(shè)置為新值newValue, //這是一個CAS操作過程,直到設(shè)置成功方能退出循環(huán),返回舊值 public final int getAndSetInt(Object o, long offset, int newValue) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, newValue)); return v; }// 1.8新增,同上,操作的是long類型 public final long getAndSetLong(Object o, long offset, long newValue) { long v; do { v = getLongVolatile(o, offset); } while (!compareAndSwapLong(o, offset, v, newValue)); return v; } //1.8新增,同上,操作的是引用類型數(shù)據(jù) public final Object getAndSetObject(Object o, long offset, Object newValue) { Object v; do { v = getObjectVolatile(o, offset); } while (!compareAndSwapObject(o, offset, v, newValue)); return v; }

CAS在java.util.concurrent.atomic相關(guān)類、Java AQS、CurrentHashMap等實現(xiàn)上有非常廣泛的應(yīng)用。

到此這篇關(guān)于Java 中的 Unsafe 魔法類的作用大全的文章就介紹到這了,更多相關(guān)Java nsafe 魔法類內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 久久精品二 | 成人免费视频播放 | 91精品国产aⅴ | 亚洲综合色视频在线观看 | 天堂欧美城网站网址 | 国产精品久久久久久久久久三级 | 日日躁夜夜操 | 国产中文字幕一区 | 亚洲精品一二三区 | 国产欧美精品一区二区三区 | 国产精品久久久久久中文字 | 国产三区在线观看视频 | 日韩av一区二区在线观看 | 国产中文字幕一区 | 国产中文在线 | 在线日韩欧美 | 久久精品成人 | 免费a视频 | 中文字幕视频在线 | 色视频www在线播放国产人成 | 色综合成人 | 999精品视频| 黄色毛片免费看 | 国产日韩中文字幕 | 久久久www成人免费精品 | 国产精品自产拍在线观看 | 成人av高清在线观看 | 久免费视频 | 91久久久久久久久 | av天天干| 久久久久久精 | 久久精品国产亚洲一区二区三区 | 国产一区二区三区免费看 | 综合五月| 久久久美女 | 中文字幕日韩视频 | 亚洲91| 久久精品国产一区二区三 | 91精品久久久久久久久入口 | www.9191| 亚洲免费av在线 | 久久se精品一区精品二区 | 精品日韩欧美一区二区在线播放 | 欧美日韩中文字幕在线 | 国产裸体永久免费视频网站 | 欧美一级在线观看 | 久久精品一区二区 | 国产99免费| 国产在线专区 | 草草视频网站 | 先锋资源av在线 | 免费黄色大片 | 成人免费视频观看视频 | 中文字幕av一区二区三区 | 久久久久免费观看 | 久久9精品 | 国产另类ts人妖一区二区 | 国产精品视频一区二区三区 | 国产亚洲一区在线 | 欧美一区二区在线播放 | 一区不卡 | 中午字幕在线观看 | 日韩欧美一区二区在线观看 | 91中文字幕 | 天天久久 | 色天天综合网 | 99精品国自产在线 | 中国免费看的片 | 综合网av| 亚洲www.| 自拍偷拍小视频 | 精品无码久久久久国产 | 四虎影院最新网址 | 特一级毛片 | 美女张开腿视频网站免费 | 久久亚洲精品裙底抄底 | 色猫猫国产区一区二在线视频 | 精品伦理一区二区三区 | 在线成人免费视频 | 日韩视频在线观看不卡 | 91精品国产91久久久久久久久久久久 | 国产成人av综合 | 日韩精品视频在线观看一区二区 | 成人国产精品视频 | 一区二区三区在线播放 | 免费网站看v片在线a | 亚洲 欧美 日韩 丝袜 另类 | 天天躁日日躁性色aⅴ电影 免费在线观看成年人视频 国产欧美精品 | 中文精品一区二区三区 | 久久成人在线视频 | 欧美日韩一区二区在线观看 | 久久丁香 | 精品久久久久久久久久久久久久 | 午夜爱爱毛片xxxx视频免费看 | 国产乱码精品一区二区三区爽爽爽 | 久久精品国产99国产精品 | 免费午夜视频 | 日本精品视频在线播放 | 成年人在线观看视频 | 成人在线播放 | 精品久久网 | 最新的黄色网址 | 欧美天天| va在线 | 成人免费共享视频 | 欧美日韩精品一区二区在线播放 | 成人精品视频在线观看 | 国产精品日本欧美一区二区三区 | 在线精品亚洲欧美日韩国产 | 久久精品店| 国产成人综合网 | 国产精品对白一区二区三区 | 国产精品欧美一区二区三区不卡 | 日韩视频在线观看视频 | 国产99精品 | 国产精品美女久久久久久久久久久 | 欧美在线操 | 日本一区二区三区在线视频 | 夜夜草视频| 成人国产| 久久99一区二区 | 国产精品视屏 | 超碰国产在线 | 国产精品美女视频免费观看软件 | 国产人妖视频 | 一区二区三区免费 | 欧美国产一区二区 | 亚洲第一区国产精品 | 国产精品久久久久久婷婷天堂 | 成人影院在线 | 国产精品婷婷久久久久 | 黄色网址大全在线观看 | 亚洲精品一区中文字幕乱码 | 欧美日韩成人一区 | 国产精品美女在线观看 | 精品久久久久久久久久久久久久 | 国产成人av电影 | 精品一区二区三区免费毛片爱 | 精品视频二区三区 | 久久久久亚洲一区二区三区 | 欧美一区二区三区免费观看视频 | 99精品视频免费在线观看 | 久久久91精品国产一区二区三区 | 国产精品久久久久久久久免费丝袜 | 91 在线 | 欧洲av在线 | 欧美精品一区二区三区蜜桃视频 | 国产色婷婷精品综合在线播放 | 日韩av在线中文字幕 | 久久精品国产清自在天天线 | 亚洲二区在线 | 一级毛片免费 | 国产精品久久久久久久久久东京 | 天天爱天天草 | 欧美亚洲专区 | 九九资源站 | 国产亚洲一区二区三区在线观看 | 青青久久久 | 久久亚洲综合 | 一区不卡 | 欧美一级网站 | 在线观看国产一区 | 欧美一区二区三区精品 | а天堂中文最新一区二区三区 | 91麻豆精品久久久久蜜臀 | 最新中文字幕久久 | 日日爽| 黄色大片在线 | 中文字幕第十二页 | 日日日操| 欧美成人精品在线观看 | 久久男人天堂 | 精品亚洲一区二区三区 | 国产无区一区二区三麻豆 | 一区二区在线播放视频 | 北条麻妃国产九九九精品小说 | 网站av | 日韩不卡中文字幕 | 国产综合亚洲精品一区二 | 台湾佬成人网 | 亚洲精品99 | 亚洲三级免费观看 | 久久人| 日本三级黄色录像 | 国产免费av大片 | 高清国产午夜精品久久久久久 | 在线观看成人 | 国产精品久久久久久久福利院 | 毛片国产| 日韩高清一区 | 亚洲国产精品一区二区久久,亚洲午夜 | 一区二区三区国产免费 | 欧美成年黄网站色视频 | 日韩视频一区在线观看 | 国内精品国产成人国产三级粉色 | 国产精品theporn | 日韩成人在线视频 | 99热69| 国产黄视频在线 | 在线观看免费视频91 | 欧美精品tv | 国产精品三级在线 | 一级黄色短片 | 国产精品高颜值在线观看 | 久热精品视频 | 一区二区三区影院 | 综合一区二区三区 | 亚洲一区中文字幕在线 | 亚洲精品乱码久久久久膏 | 蜜臀久久99精品久久久无需会员 | 中文字幕 在线观看 | 免费毛片大全 | 91免费看片神器 | 免费毛片网站 | 黄色在线免费看 | 欧美午夜在线观看 | 成人国产在线 | 操老逼 | 国产精品27页 | 毛片一区二区 | 国产成人一区 | 日本成人三级 | 午夜午夜精品一区二区三区文 | 伊人一区 | 性色视频在线 | 精品 99 | 午夜免费影视 | 国产欧美综合一区二区三区 | 午夜在线电影 | 精品国产不卡一区二区三区 | eeuss国产一区二区三区四区 | 一区二区av在线 | 久久久久中文 | 亚洲一区二区三区中文字幕 | 精品一区二区在线观看 | 精品一区二区久久久久久久网站 | 日韩欧美一级精品久久 | 亚洲一区中文 | 日韩www视频 | 欧美一二三四成人免费视频 | 国内自拍偷拍视频 | 亚洲欧美精品 | 亚洲一区欧美 | 精品久久久久久久久久久久久久久 | 成人综合在线观看 | 国产一区二区在线免费观看 | 久久99久久99精品免观看粉嫩 | 亚洲精品久久久一区二区三区 | 欧美日韩精品一区二区在线播放 | zzzwww在线观看免 | 国产成人免费视频网站视频社区 | 精品视频一区二区三区四区 | 正在播放国产精品 | wwwjizz日本 | 精品国产一区二区在线 | 探花在线观看 | 91久久精品国产91久久性色tv | 国产一区二区三区在线免费 | 天堂资源在线 | 亚洲精选久久 | 久久久91精品国产一区二区三区 | 国产免费自拍 | 亚洲视频三区 | 成人中文字幕在线 | 先锋资源av在线 | 国内精品一区二区 | 在线看91 | 91精品国产综合久久久久久 | 欧美大片一区二区 | a免费在线观看 | 依人成人综合网 | 午夜小视频在线观看 | 99精品视频在线观看 | 91久久艹| 精品一区二区三区在线观看 | 国产免费一区 | 午夜欧美 | 亚洲天堂第一页 | 欧美区视频 | 小草av| 国产最新网站 | 久久精品超碰 | 久久久久综合 | 这里有精品视频 | 亚洲国产中文字幕 | 久久99这里只有精品 | 国产日韩久久 | 看毛片软件 | 国产激情视频网 | 欧美在线视频一区二区 | 这里精品| 欧美video| 欧美日韩国产一级片 | 成人免费在线电影 | 精品国产第一国产综合精品 | 最新日韩在线观看视频 | 男女www视频 | 日韩电影在线看 | 欧美a级成人淫片免费看 | 日韩中文字幕在线播放 | 91久久91久久精品免观看 | 国产视频一视频二 | 日韩精品在线播放 | 日本国产一区二区 | 欧美国产日韩精品 | 色噜噜视频在线观看 | 91日韩欧美| 成人免费视频视频在线观看 免费 | 天天澡天天狠天天天做 | 少妇无套高潮一二三区 | 欧美日韩激情一区二区三区 | 99精品国产高清一区二区麻豆 | 999视频在线免费观看 | 欧美激情在线播放 | 欧美中文在线 | 亚洲精品1 | 日本电影网址 | 最近中文字幕在线视频1 | 成人av影片在线观看 | 亚洲不卡视频 | 一本一道久久a久久精品综合 | 国产91看片 | 成人亚洲精品777777大片 | 欧美日韩一区二区三区在线观看 | 国产三级久久久久 | 亚洲欧美国产精品专区久久 | 久久男女 | 成人午夜精品一区二区三区 | 久久久久久亚洲精品 | 欧美综合在线观看 | 国产精品久久久久久吹潮 | 国产成人精品久久二区二区91 | 日本精品999| www.亚洲| 久久av一区 | 久久久久一区二区三区 | 精品久| 久久欧美精品 | 国产在线激情视频 | 精品久久久久久国产 | 黄色毛片在线观看 | 欧美在线观看免费观看视频 | 九九精品视频在线观看 | 日韩欧美中文字幕在线视频 | 色无欲天天天影视综合网 | 精品成人网 | 成人一区二区在线 | 欧美在线视频播放 | 福利视频网站 | 日韩精品久久久久久 | 黄色骚片| 国产精品女教师av久久 | 国产成人在线视频 | 日韩久久久一区二区 | 美日韩精品视频 | 中文字幕久久精品 | 黄的视频网站 | 狠狠躁夜夜躁人人爽天天高潮 | 九热精品 | 一区二区精品 | 一区二区三区不卡视频 | 伊人精品 | 亚洲国产高清高潮精品美女 | 在线观看精品91福利 | 粉嫩国产精品一区二区在线观看 | 国产乱码精品一区二区三区av | 一级在线观看 | 美女吊逼 | 毛片a级片| 国产精品久久久久久二区 | 国产精品九九九 | 高清av一区 | 精品一二三区 | 国产成人精品一区一区一区 | 国产免费一区二区三区网站免费 | 国产精品久久久久久久久久东京 | 亚洲成年片 | 免费大片在线观看网站 | 欧美成人精品一区二区男人看 | 久久综合久久受 | 国产在线一区不卡 | 久久久网 | 羞羞视频在线免费 | 精品无码三级在线观看视频 | 天天久| 日韩一区二区三区在线 | 欧美一区二 | 亚洲黄色一区二区 | 欧美成人精品 | 九九久久精品 | 69久久99精品久久久久婷婷 | 久久综合伊人 | 亚洲欧美日韩国产综合 | 久久一| 亚洲在线观看免费视频 | 亚洲成人av一区二区三区 | 国产美女在线观看 | 91精品国产综合久久久久久漫画 | 国产精品久久久久久亚洲调教 | 亚洲综合区 | 91午夜精品 | 9999国产精品 | 成人精品| 四虎影院最新网站 | 黄理论视频 | 成人精品 | 久久精彩视频 | 欧洲毛片 | 亚洲福利社区 | 欧美另类一区二区 | 欧美精品一区二区三区四区 | 国产一区在线看 | 日韩三级在线 | 国产精品丝袜视频 | 成人av入口 | 亚洲午夜视频在线观看 | 伊人网在线视频 | 国产精品自产拍在线观看 | 自拍视频免费 | 精品在线视频一区 | 久久加勒比 | 国产1区2区3区 | www.色综合| 国模一区二区三区 | 欧美日韩国产综合网 | 亚洲免费视频在线观看 | 91一区二区 | 欧美一区二区大片 | 久久草视频 | 欧美日韩国产在线 | www.日韩.com| 一区二区三区四区 | 三级色网站 | 日韩在线免费视频 | 成人在线视频一区二区 | 日本亚洲精品一区二区三区 | 亚洲一区二区三区免费看 | 性色爽爱 | 91视频在线观看 | 欧美78videosex性欧美 | 91在线精品视频 | 日韩一区二区在线播放 | 亚洲精品国精品久久99热 | 亚洲乱码国产乱码精品精98午夜 | 亚洲国产精品一区二区www | 国产精品无码久久久久 | 日本在线免费电影 | 亚洲欧洲在线观看 | 国产精品久久久久久久久久 | 中文字幕亚洲欧美日韩在线不卡 | 中文字幕亚洲欧美 | 黄色av毛片| 三级成人在线 | 亚洲精品影院 | 精品国产一级片 | 蜜桃色网 | 欧美日在线 | 性色爽爱 | 欧美性猛交xxxx黑人猛交 | 美女操网站 | 国产一区欧美 | 久草成人网 | 欧美久久久久 | 欧美成人精品在线 | 四虎影院观看 | 4h影视| 一区二区中文字幕 | 国产精品毛片一区二区 | 香蕉久久久久久 | 91视频电影 | 男女视频在线 | 欧美区国产区 | 狠狠干干 | 一区二区久久 | 国产精品免费观看 | 欧美一区二区黄色片 | 国产超碰在线 | 国产一区二 | 国产精品自产拍在线观看 | 欧美一级在线播放 | 日韩特黄一级欧美毛片特黄 | 99视频这里有精品 | 日韩超碰在线观看 | 午夜精品久久久久久久白皮肤 | 亚洲精品久久久久久下一站 | 精品91| 日本一区二区精品视频 | 欧美嘿咻 | 久久99久久久久久 | 日韩国产欧美 | 在线免费观看毛片 | 欧美成人免费一级人片100 | 不卡一二区 | 一区二区三区高清 | 一区二区视频在线 | 一区二区三区精品视频 | av在线精品 | 欧美区在线 | 亚洲一区二区av | 久久这里只有精品8 | 久久久久久免费看 | 香蕉婷婷 | 亚洲免费一区 | 国产一区av在线 | 成人免费一区二区三区视频网站 | 日日爱夜夜操 | 国产高清久久久 | 999久久久国产精品 免费视频一区 | 久久精品免费观看视频 | 国产中文一区二区三区 | 精品国产精品三级精品av网址 | 成人免费一区二区三区视频软件 | 成人午夜电影在线 | 中文字幕在线观看亚洲 | 日本免费一区二区三区 | 国产精品久久久久久久免费大片 | 91在线精品秘密一区二区 | 欧美成人激情视频 | 男女视频免费看 | 黄色片网站 | 欧美视频免费看 | 午夜免费观看网站 | 国产精品一区一区三区 | www.久久久久 | 日韩精品免费在线观看 | 国产精品国色综合久久 | 亚洲成人久久久 | 国产精品电影 | 亚洲啊v | 青草福利 | 欧美a v在线播放 | 91视频免费在线看 | 午夜在线观看视频网站 | 日韩视频精品在线观看 | 韩国三级中文字幕hd久久精品 | 久久久精品国产 | 日本午夜在线 | 欧美午夜视频 | 曰韩毛片| 欧美黄色a视频 | 国产成人午夜 | 国产欧美精选 | 国产精品久久99 | 欧美第一区 | 九九九久久久 | 国产高清在线a视频大全 | av网站观看 | 日韩精品视频久久 | 免费亚洲一区二区 | 欧美污污 | 一区二区三区在线播放 | 最新天堂中文在线 | 日本欧美在线 | 国产色 | 国产精品原创av片国产免费 | 青青草视频免费观看 | 精品国产乱码久久久久久影片 | 性色av一区二区三区 | 成人免费毛片高清视频 | 一级毛片免费看 | 欧美激情综合五月色丁香小说 | 久久久精品日本 | 狠狠综合久久 | 国产美女福利在线 | 日韩网站免费观看 | 欧美日韩电影一区 | 成人精品免费视频 | 久久叉| 欧美天堂在线观看 | 香港三级日本三级a视频 | 看特级毛片 | 91免费在线视频 | 中文字幕一区日韩精品欧美 | 成人一级片 | 伊人爽| 欧美久久a | 午夜影晥 | 亚洲成熟少妇视频在线观看 | 亚洲综合一区二区三区 | 91视频久久| 日韩av在线中文字幕 | 欧美日本亚洲 | 国产青青草 | 一级毛片视频 | 日本三级黄色录像 | 色婷网 | 亚洲视频在线观看免费 | 精品亚洲区 | 日韩精品一区二区三区中文字幕 | 国产精品视频久久久 | 国产成人精品一区二区 | 禁果av一区二区三区 | 在线免费91 | 欧美在线| 久久成人国产精品 | 亚洲国内精品 | 午夜在线视频免费观看 | 亚洲一区二区中文 | 亚洲网站在线观看 | 古风h啪肉1v1摄政王 | 精品一二区 | 欧美日韩国产综合视频 | 欧美一区二区三区xxxx监狱 | av看片网| 久久精品国产亚洲一区二区三区 | 粉嫩国产精品一区二区在线观看 | 日韩在线免费 | 中文字幕乱码亚洲精品一区 | 精品美女久久久 | 久久五月视频 | 国产精品美女久久久久久免费 | 日韩在线一区二区 | 国产成人精品综合 | 午夜社区 | 国产成人精品一区一区一区 |