ทำไม sun.misc.Unsafe มีอยู่และมันสามารถใช้ในโลกแห่งความจริงได้อย่างไร? [ปิด]


267

ฉันมาเจอดวงอาทิตย์หลายวันแพคเกจที่ไม่ปลอดภัยในวันอื่นและรู้สึกประหลาดใจกับสิ่งที่สามารถทำได้

แน่นอนว่าชั้นเรียนไม่มีเอกสาร แต่ฉันสงสัยว่ามีเหตุผลที่ดีที่จะใช้หรือไม่ สถานการณ์ใดบ้างที่อาจเกิดขึ้นซึ่งคุณจำเป็นต้องใช้ มันจะนำไปใช้ในสถานการณ์จริงได้อย่างไร?

นอกจากนี้ถ้าคุณทำต้องการมันไม่ว่าได้ระบุสิ่งที่อาจจะเป็นความผิดที่มีการออกแบบของคุณหรือไม่

ทำไมจาวาถึงมีคลาสนี้ด้วย?


7
devs JDK กำลังตรวจสอบ API นี้สำหรับการเปลี่ยนแปลงที่เป็นไปได้เป็นประชาชน API ในชวา 9. ถ้าคุณใช้มันของมูลค่าการ 5 นาทีในการกรอกแบบสำรวจ: surveymonkey.com/s/sun-misc-Unsafe
Andy Lynch

2
โพสต์นี้กำลังถูกกล่าวถึงใน meta: meta.stackoverflow.com/questions/299139/…
Jon Clements

คำตอบ:


159

ตัวอย่าง

  1. VM "การทำให้เป็น intrinsification" เช่น CAS (เปรียบเทียบและสลับ) ที่ใช้ในตารางแฮชล็อคฟรีเช่น: sun.misc.Unsafe.compareAndSwapInt ซึ่งสามารถทำการโทร JNI จริงเป็นรหัสพื้นเมืองที่มีคำแนะนำพิเศษสำหรับ CAS

    อ่านเพิ่มเติมเกี่ยวกับ CAS ได้ที่นี่http://en.wikipedia.org/wiki/Compare-and-swap

  2. ฟังก์ชัน sun.misc.Unsafe ของโฮสต์ VM สามารถใช้เพื่อจัดสรรวัตถุที่ไม่มีการกำหนดค่าเริ่มต้นแล้วตีความการเรียกใช้คอนสตรัคเตอร์เป็นการเรียกใช้เมธอดอื่น ๆ

  3. หนึ่งสามารถติดตามข้อมูลจากที่อยู่พื้นเมืองมันเป็นไปได้ที่จะดึงที่อยู่หน่วยความจำของวัตถุโดยใช้คลาส java.lang.Unsafe และดำเนินการในสาขาโดยตรงผ่านวิธีการรับ / วางที่ไม่ปลอดภัย!

  4. รวบรวมการออปติไมซ์เวลาสำหรับ JVM VM ประสิทธิภาพสูงโดยใช้ "magic" ต้องการการดำเนินงานระดับต่ำ เช่น: http://en.wikipedia.org/wiki/Jikes_RVM

  5. การจัดสรรหน่วยความจำ sun.misc.Unsafe.allocateMemory เช่น: - ตัวสร้าง DirectByteBuffer เรียกภายในเมื่อ ByteBuffer.allocateDirect ถูกเรียกใช้

  6. ติดตาม call stack และการเล่นซ้ำด้วยค่าที่ instantiated โดย sun.misc.Unsafe มีประโยชน์สำหรับการใช้เครื่องมือ

  7. sun.misc.Unsafe.arrayBaseOffset และ arrayIndexScale สามารถใช้ในการพัฒนา arraylets ซึ่งเป็นเทคนิคในการแยกอาร์เรย์ขนาดใหญ่อย่างมีประสิทธิภาพลงในวัตถุขนาดเล็กเพื่อ จำกัด ต้นทุนการสแกนปรับปรุงหรือย้ายวัตถุแบบเรียลไทม์

  8. http://robaustin.wikidot.com/how-to-write-to-direct-memory-locations-in-java

เพิ่มเติมเกี่ยวกับการอ้างอิงที่นี่ - http://bytescrolls.blogspot.com/2011/04/interesting-uses-of-sunmiscunsafe.html


1
หากคุณได้รับที่อยู่ของเขตข้อมูลโดยใช้ไม่ปลอดภัยสามารถเปลี่ยนแปลงได้โดย GC ดังนั้นการดำเนินการดังกล่าวจึงไม่มีประโยชน์เลยใช่ไหม
pdeva

รับที่อยู่สำหรับที่อยู่ที่คุณจัดสรร
zudokod

คุณหมายถึงอะไรโดยคนที่ฉันจัดสรร ดูเหมือนว่าจะใช้ในสถานที่ที่วัตถุถูกสร้างขึ้นโดยใช้ตัวดำเนินการ 'ใหม่' ดังนั้นคำถามของฉัน
pdeva

1
unsafe.allocateMemory และใส่ค่า
zudokod

1
เกี่ยวกับประเด็นที่ 2 ฉันอยากรู้ว่าคุณจะเรียกนวกรรมิกได้อย่างไรเมื่อมีการเรียกเมธอดอื่น เพราะฉันไม่พบวิธีการใด ๆ ที่จะทำยกเว้นในไบต์
Miguel Gamboa

31

เพียงแค่เรียกใช้การค้นหาในเครื่องมือค้นหารหัสฉันได้รับตัวอย่างต่อไปนี้:

  • Java Object Notation - ใช้เพื่อการประมวลผลอาเรย์ที่มีประสิทธิภาพยิ่งขึ้นโดยอ้างถึง javadoc

คลาสแบบง่าย ๆ เพื่อรับการเข้าถึงวัตถุ {@link Unsafe} {@link Unsafe} * จำเป็นเพื่อให้การดำเนินการ CAS มีประสิทธิภาพในอาร์เรย์ โปรดทราบว่ารุ่นใน {@link java.util.concurrent.atomic} เช่น {@link java.util.concurrent.atomic.AtomicLongArray} ต้องการการรับประกันหน่วยความจำเพิ่มเติมซึ่งโดยทั่วไปไม่จำเป็นต้องใช้ในอัลกอริธึมเหล่านี้และยังมีราคาแพง บนโปรเซสเซอร์ส่วนใหญ่

  • SoyLatte - java 6 สำหรับ osx javadoc excerpt

/ ** คลาสพื้นฐานสำหรับ FieldAccessors ที่ใช้ sun.misc.Unsafe สำหรับฟิลด์คงที่ การสังเกตคือว่ามีเพียงเก้าประเภทของเขตข้อมูลจากมุมมองของรหัสการสะท้อน: แปดประเภทดั้งเดิมและวัตถุ การใช้คลาสที่ไม่ปลอดภัยแทนการสร้าง bytecode จะช่วยประหยัดหน่วยความจำและเวลาโหลดสำหรับ FieldAccessors ที่สร้างขึ้นแบบไดนามิก * /

  • SpikeSource

/ * FinalFields ที่ถูกส่งข้ามเส้นลวด .. จะ unmarshall และสร้างวัตถุบนฝั่งรับได้อย่างไร? เราไม่ต้องการเรียกใช้ตัวสร้างเนื่องจากมันจะสร้างค่าสำหรับฟิลด์สุดท้าย เราต้องสร้างฟิลด์สุดท้ายขึ้นใหม่เหมือนที่อยู่ในฝั่งผู้ส่ง พระอาทิตย์ตก. ไม่ปลอดภัยทำสิ่งนี้เพื่อเรา * /

มีตัวอย่างอื่น ๆ อีกมากมายเพียงไปที่ลิงก์ด้านบน ...


25

น่าสนใจฉันไม่เคยได้ยินวิชานี้เลย (ซึ่งน่าจะเป็นสิ่งที่ดีจริงๆ)

สิ่งหนึ่งที่ต้องคำนึงถึงคือการใช้Unsafe # setMemoryเพื่อทำให้บัฟเฟอร์เป็นศูนย์ที่มีข้อมูลที่ละเอียดอ่อน ณ จุดหนึ่ง (รหัสผ่าน, คีย์, ... ) คุณสามารถทำสิ่งนี้กับสาขาของวัตถุ "ไม่เปลี่ยนรูป" (อีกครั้งฉันคิดว่าการสะท้อนเก่าแบบธรรมดาอาจทำเคล็ดลับที่นี่ด้วย) ฉันไม่มีผู้เชี่ยวชาญด้านความปลอดภัย แต่เอามาด้วยเม็ดเกลือ


4
I'd never even heard of this class... ฉันบอกคุณหลายครั้งแล้ว! ถอนหายใจ + :(
ทิมเบนเดอร์

7
คงไม่มีประเด็นใดที่จะเกิดขึ้นเนื่องจาก Java ใช้ตัวคัดลอกขยะทั่วไปและข้อมูลที่ละเอียดอ่อนของคุณอาจจะอยู่ในที่อื่นในหน่วยความจำ 'ฟรี' ที่รอการเขียนทับ
Daniel Cassidy

39
ไม่เคยได้ยินเลย แต่ฉันชอบpark()เอกสารของพวกเขา: "บล็อกเธรดปัจจุบัน, ส่งคืนเมื่อเกิด unpark ที่สมดุลหรือมี unpark สมดุลเกิดขึ้นแล้วหรือเธรดถูกขัดจังหวะหรือถ้าไม่แน่นอนและเวลาไม่เป็นศูนย์ เวลา nanoseconds ที่กำหนดได้ผ่านไปหรือหากสัมบูรณ์กำหนดเวลาที่กำหนดเป็นมิลลิวินาทีนับตั้งแต่ยุคได้ผ่านไปแล้วหรือฉ้อโกง (เช่นกลับมาโดยไม่มีเหตุผล ') " เกือบจะดีเท่ากับ "หน่วยความจำจะถูกปล่อยให้เป็นอิสระเมื่อโปรแกรมออกหรือตามช่วงเวลาแบบสุ่มแล้วแต่ว่าจะถึงอย่างใดก่อน"
aroth

1
@Daniel น่าสนใจฉันไม่ได้คิดอย่างนั้น ตอนนี้คุณสามารถเห็นได้ว่าทำไมฉันถึงไม่ใช่ผู้เชี่ยวชาญด้านความปลอดภัย :)
Mike Daniels

22

จากการวิเคราะห์อย่างย่อ ๆ ของไลบรารี Java 1.6.12 ที่ใช้ eclipse สำหรับการติดตามการอ้างอิงดูเหมือนว่าทุกฟังก์ชันการทำงานที่มีประโยชน์ของUnsafeจะเปิดเผยในวิธีที่มีประโยชน์

การทำงานของ CAS ได้รับการเปิดเผยผ่านคลาส Atomic * ฟังก์ชั่นการปรับเปลี่ยนหน่วยความจำได้รับการเปิดเผยผ่านคำสั่ง DirectByteBuffer Sync (park, unpark) ผ่านทาง AbstractQueuedSynchronizer ซึ่งจะถูกใช้โดยการใช้งานการล็อค


AtomicXXXUpdaters ช้าเกินไปและเมื่อคุณต้องการ: CAS - คุณไม่สามารถใช้งานได้จริง หากคุณกำลังจะทำโลหะคุณจะไม่ใช้ระดับที่เป็นนามธรรมและเช็คจำนวนมาก ความล้มเหลวของ CAS เป็นสิ่งที่แย่ในลูป esp เมื่อฮาร์ดแวร์ตัดสินใจที่จะคาดคะเนสาขา (เนื่องจากการแข่งขันสูง) แต่มีการเปรียบเทียบ / สาขาเพียงไม่กี่เจ็บเท่านั้น Park / Unpark ถูกเปิดเผยผ่านLockSupportไม่ใช่ AQS (หลังนั้นมีความหมายมากกว่าการล็อค / unpark)
bestsss

21

Unsafe.throwException - อนุญาตให้โยนข้อยกเว้นที่เลือกโดยไม่ต้องแจ้งให้ทราบ

สิ่งนี้มีประโยชน์ในบางกรณีที่คุณจัดการกับภาพสะท้อนหรือ AOP

สมมติว่าคุณสร้างพร็อกซีทั่วไปสำหรับส่วนต่อประสานที่ผู้ใช้กำหนด และผู้ใช้สามารถระบุข้อยกเว้นที่จะถูกโยนโดยการรวมในกรณีพิเศษเพียงแค่ประกาศข้อยกเว้นในอินเทอร์เฟซ จากนั้นเป็นวิธีเดียวที่ฉันรู้เพื่อเพิ่มข้อยกเว้นที่ตรวจสอบในการใช้งานแบบไดนามิกของอินเทอร์เฟซ

import org.junit.Test;
/** need to allow forbidden references! */ import sun.misc.Unsafe;

/**
 * Demonstrate how to throw an undeclared checked exception.
 * This is a hack, because it uses the forbidden Class {@link sun.misc.Unsafe}.
 */
public class ExceptionTest {

    /**
     * A checked exception.
     */
    public static class MyException extends Exception {
        private static final long serialVersionUID = 5960664994726581924L;
    }

    /**
     * Throw the Exception.
     */
    @SuppressWarnings("restriction")
    public static void throwUndeclared() {
        getUnsafe().throwException(new MyException());
    }

    /**
     * Return an instance of {@link sun.misc.Unsafe}.
     * @return THE instance
     */
    @SuppressWarnings("restriction")
    private static Unsafe getUnsafe() {
        try {

            Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
            singleoneInstanceField.setAccessible(true);
            return (Unsafe) singleoneInstanceField.get(null);

        } catch (IllegalArgumentException e) {
            throw createExceptionForObtainingUnsafe(e);
        } catch (SecurityException e) {
            throw createExceptionForObtainingUnsafe(e);
        } catch (NoSuchFieldException e) {
            throw createExceptionForObtainingUnsafe(e);
        } catch (IllegalAccessException e) {
            throw createExceptionForObtainingUnsafe(e);
        }
    }

    private static RuntimeException createExceptionForObtainingUnsafe(final Throwable cause) {
        return new RuntimeException("error while obtaining sun.misc.Unsafe", cause);
    }


    /**
     * scenario: test that an CheckedException {@link MyException} can be thrown
     * from an method that not declare it.
     */
    @Test(expected = MyException.class)
    public void testUnsingUnsaveToThrowCheckedException() {
        throwUndeclared();
    }
}

14
คุณสามารถทำสิ่งเดียวกันโดยThread.stop(Throwable)ไม่จำเป็นต้องไม่ปลอดภัยในหัวข้อเดียวกันคุณสามารถโยนสิ่งใด ๆ (ไม่มีการตรวจสอบการคอมไพล์)
bestsss

คุณสามารถทำสิ่งนี้ได้อย่างหมดจดด้วย bytecode (หรือใช้ Lomboc เพื่อทำเพื่อคุณ)
Antimony

1
@bestsss วิธีการนั้นได้รับการ stubbed out และส่งออกไปUnsupportedOperationExceptionในเธรดปัจจุบัน ณ Java 8 อย่างไรก็ตามเวอร์ชันที่ไม่มีการโต้แย้งที่ThreadDeathยังคงใช้งานได้
gparyani

@damryfbfnetsi ฉันไม่ได้ติดตาม core jdk สำหรับการสนทนาและไม่มีแผนจะย้ายไปที่จาวา 8 แต่นี่เป็นความคิดที่น่าสงสัยเพราะมันเป็นเรื่องเล็กน้อยที่จะถูกนำมาใช้โดย bytecode generation anyways เว้นแต่ตอนนี้ผู้ตรวจสอบจะตรวจสอบจริงหรือไม่ วิธีการประกาศ Throwables ... แต่ที่อาจจะย้อนกลับไม่เข้ากันเป็นเมตาดาต้าเกี่ยวกับข้อยกเว้นโยนมีอิสระที่จะถูกทิ้ง
bestsss

10

ระดับไม่ปลอดภัย

คอลเล็กชันของเมธอดสำหรับการดำเนินการระดับต่ำและไม่ปลอดภัย แม้ว่าคลาสและเมธอดทั้งหมดเป็นแบบสาธารณะการใช้คลาสนี้มี จำกัด เนื่องจากรหัสที่เชื่อถือได้เท่านั้นที่สามารถรับอินสแตนซ์ของมันได้

หนึ่งการใช้งานของมันอยู่ในjava.util.concurrent.atomicชั้นเรียน:


6

สำหรับการคัดลอกหน่วยความจำที่มีประสิทธิภาพ (เร็วกว่าการคัดลอกกว่า System.arraycopy () สำหรับบล็อกสั้นอย่างน้อย); ตามที่ใช้โดยตัวแปลงสัญญาณJava LZFและSnappy พวกเขาใช้ 'getLong' และ 'putLong' ซึ่งเร็วกว่าการทำสำเนาไบต์ต่อไบต์ มีประสิทธิภาพโดยเฉพาะอย่างยิ่งเมื่อคัดลอกสิ่งต่าง ๆ เช่นบล็อกขนาด 16/32/64 ไบต์


1
Doh, arraycopy ใช้ลูป SSE บน x86-64 ซึ่งดีกว่าgetLong/putLong(และคุณต้องคำนวณที่อยู่ด้วย)
bestsss

คุณวัดสิ่งนี้จริงหรือ สำหรับบล็อกที่สั้นกว่าฉันเห็นประสิทธิภาพที่ดีขึ้นอย่างต่อเนื่องใน x86-64 เมื่อใช้การรวมกันของgetLong/ putLong: โดยเฉพาะฉันต้องการSystem.arraycopy()ความเรียบง่ายและทั้งหมด; แต่การทดสอบจริงแสดงให้เห็นเป็นอย่างอื่นสำหรับกรณีที่ฉันทดสอบ
StaxMan

ใช่ใช้ไม่ปลอดภัยฉันไม่สามารถแสดงประสิทธิภาพที่มีความหมายใด ๆ สำหรับหลาย ๆ ไบต์ที่มีความยาวมากกว่าอาร์เรย์ขนาดใหญ่ที่ได้รับ / putLong อาจทำงานได้อย่างแท้จริงเมื่อคอมไพเลอร์ต้องตรวจสอบความยาว บางคนแปลว่า เพิ่มรั้วหน่วยความจำที่ผ่านมา System.arrayCopy (สามารถปิดการใช้งาน / เปิดใช้งานแม้ว่า) ดังนั้นที่อาจเป็นผู้ร้ายจริง
bestsss

ตกลง. เป็นไปได้ว่า JDK ที่ใหม่กว่าได้เปลี่ยนแปลงสิ่งนี้ แต่เดิมเมื่อฉันสังเกตการทำงานที่เร็วขึ้น (ด้วย JDK 1.6) ฉันก็ประหลาดใจเช่นกัน หรือบางทีฉันอาจลืมความแตกต่างในการใช้งานบางอย่าง สิ่งเหล่านี้คือการปรับให้เหมาะสม (และอาจไม่เสถียร) ที่ซับซ้อนแม้ว่าจะทำงานและมันก็เป็นสิ่งสำคัญในการวัดผลกระทบ
StaxMan

5

ผมได้รับเมื่อเร็ว ๆ นี้การทำงานใน reimplementing JVM Unsafeที่และพบว่าเป็นจำนวนที่น่าแปลกใจของการเรียนจะดำเนินการในแง่ของ ชั้นเรียนส่วนใหญ่ได้รับการออกแบบสำหรับผู้ใช้งานห้องสมุด Java และมีคุณสมบัติที่ไม่ปลอดภัยขั้นพื้นฐาน แต่จำเป็นสำหรับการสร้างดั้งเดิมอย่างรวดเร็ว ตัวอย่างเช่นมีวิธีการในการรับและเขียนออฟเซ็ตเขตข้อมูลดิบโดยใช้การซิงโครไนซ์ระดับฮาร์ดแวร์การจัดสรรและการเพิ่มหน่วยความจำและอื่น ๆ มันไม่ได้ตั้งใจที่จะใช้โดยโปรแกรมเมอร์ Java ปกติ; มันไม่มีเอกสารการใช้งานเฉพาะและไม่ปลอดภัยโดยเนื้อแท้ (จึงเป็นชื่อ!) ยิ่งกว่านั้นฉันคิดว่ามันSecurityManagerจะไม่อนุญาตการเข้าถึงในเกือบทุกกรณี

กล่าวโดยสรุปแล้วส่วนใหญ่มีอยู่เพื่อให้ผู้ใช้ไลบรารีสามารถเข้าถึงเครื่องต้นแบบได้โดยไม่ต้องประกาศทุกวิธีในบางคลาสเช่นAtomicIntegerเนทีฟ คุณไม่จำเป็นต้องใช้หรือกังวลกับมันในการเขียนโปรแกรม Java ตามปกติจุดรวมคือการทำให้ส่วนที่เหลือของห้องสมุดเร็วพอที่คุณจะไม่ต้องการการเข้าถึงแบบนั้น


อันที่จริง SecurityManager ไม่อนุญาตให้เข้าถึงหากการสะท้อนถูกปิดใช้งาน
amara

@ sparkleshy- คุณช่วยอธิบายเรื่องนี้ได้ไหม?
templatetypedef

ในขณะที่ได้รับอินสแตนซ์จาก getUnsafe มีข้อกำหนดที่ค่อนข้างเข้มงวดUnsafe.class.getDeclaredField("theUnsafe")ด้วย.setAccessible(true)และจากนั้นก็.get(null)จะได้รับเช่นกัน
amara

@ sparkleshy- ฉันประหลาดใจที่ได้ผล - ผู้จัดการความปลอดภัยควรตั้งค่าสถานะนั้น
templatetypedef

5

ใช้เพื่อเข้าถึงและจัดสรรหน่วยความจำจำนวนมากอย่างมีประสิทธิภาพเช่นในเครื่องมือ voxel ของคุณเอง! (เช่นเกมสไตล์ Minecraft)

จากประสบการณ์ของฉัน JVM มักไม่สามารถกำจัดขอบเขตการตรวจสอบในสถานที่ที่คุณต้องการอย่างแท้จริง ตัวอย่างเช่นหากคุณวนซ้ำอาร์เรย์ขนาดใหญ่ แต่การเข้าถึงหน่วยความจำจริงถูกซ่อนอยู่ภายใต้การเรียกใช้เมธอดที่ไม่ใช่เสมือนในลูป JVM อาจยังคงตรวจสอบขอบเขตกับการเข้าถึงอาเรย์แต่ละครั้ง ห่วง ดังนั้นเพื่อให้ได้ประสิทธิภาพที่มากขึ้นคุณสามารถกำจัดการตรวจสอบขอบเขต JVM ภายในลูปผ่านวิธีการที่ใช้ sun.misc.Unsafe เพื่อเข้าถึงหน่วยความจำโดยตรงตรวจสอบให้แน่ใจว่าได้ทำการตรวจสอบตัวเองในสถานที่ที่ถูกต้อง (คุณเป็นไงขอบเขตการตรวจสอบในระดับบางอย่างใช่ไหม?)
* โดยที่ไม่ใช่เสมือนฉันหมายความว่า JVM ไม่ควรแก้ไขแบบไดนามิกไม่ว่าวิธีการเฉพาะของคุณคืออะไรเพราะคุณรับประกันได้อย่างถูกต้องว่าคลาส / วิธี / อินสแตนซ์เป็นการผสมผสานระหว่างสแตติก / ขั้นสุดท้าย / สิ่งที่มี

สำหรับเครื่องยนต์ voxel ที่ปลูกในบ้านของฉันสิ่งนี้ส่งผลให้ประสิทธิภาพเพิ่มขึ้นอย่างมากในระหว่างการสร้างและการจัดลำดับ (สถานที่ที่ฉันอ่าน / เขียนไปยังอาร์เรย์ทั้งหมดในครั้งเดียว) ผลลัพธ์อาจแตกต่างกันไป แต่ถ้าไม่มีปัญหาการกำจัดขอบเขตของคุณแล้วสิ่งนี้จะแก้ไขได้

มีปัญหาบางอย่างที่อาจเกิดขึ้นกับสิ่งนี้: โดยเฉพาะเมื่อคุณให้ความสามารถในการเข้าถึงหน่วยความจำโดยไม่ จำกัด ขอบเขตการตรวจสอบกับลูกค้าของอินเทอร์เฟซของคุณพวกเขาอาจจะละเมิดมัน (อย่าลืมว่าแฮ็กเกอร์อาจเป็นลูกค้าของส่วนต่อประสานของคุณ ... โดยเฉพาะอย่างยิ่งในกรณีของเครื่องมือ voxel ที่เขียนด้วยภาษาจาวา) ดังนั้นคุณควรออกแบบส่วนต่อประสานของคุณในลักษณะที่หน่วยความจำเข้าถึงไม่ได้ คุณควรจะระมัดระวังอย่างมากในการตรวจสอบข้อมูลผู้ใช้ก่อนที่จะสามารถที่เคยเคยคลาคล่ำด้วยอินเตอร์เฟซที่เป็นอันตรายของคุณ เมื่อพิจารณาถึงความหายนะที่แฮ็กเกอร์สามารถทำได้ด้วยการเข้าถึงหน่วยความจำที่ไม่ได้ตรวจสอบมันอาจเป็นการดีที่สุดที่จะใช้วิธีทั้งสอง


4

คอลเลกชัน Off-heap อาจมีประโยชน์สำหรับการจัดสรรหน่วยความจำจำนวนมากและยกเลิกการจัดสรรคืนทันทีหลังจากใช้โดยไม่มีการรบกวน GC ผมเขียนห้องสมุดสำหรับการทำงานกับปิดกองอาร์เรย์ / sun.misc.Unsafeรายการตาม


4

เราได้ใช้คอลเลกชันขนาดใหญ่เช่นอาร์เรย์ HashMaps, TreeMaps โดยใช้ไม่ปลอดภัย
และเพื่อหลีกเลี่ยง / ลดการแตกแฟรกเมนต์เราจึงใช้ตัวจัดสรรหน่วยความจำโดยใช้แนวคิดของdlmallocบนที่ไม่ปลอดภัย
สิ่งนี้ช่วยให้เราได้รับประสิทธิภาพในการทำงานพร้อมกัน


3

Unsafe.park()และUnsafe.unpark()สำหรับการสร้างโครงสร้างการควบคุมภาวะพร้อมกันและกลไกการตั้งเวลาแบบมีส่วนร่วม


24
แบบสาธารณะให้บริการในฐานะjava.util.concurrent.locks.LockSupport
bestsss

1

ยังไม่ได้ใช้ด้วยตนเอง แต่ฉันคิดว่าถ้าคุณมีตัวแปรที่บางครั้งอ่านโดยเธรดมากกว่าหนึ่งครั้งเท่านั้น (ดังนั้นคุณไม่ต้องการทำให้มันผันผวน) คุณสามารถใช้putObjectVolatileเมื่อเขียนมันในเธรดหลักและreadObjectVolatileเมื่อทำการอ่านหายากจากกระทู้อื่น ๆ


1
แต่จากการพูดคุยในหัวข้อด้านล่างสารระเหยที่ไม่มีการ
จดสิทธิบัตร

คุณไม่สามารถแทนที่ซีแมนทิกส์แบบระเหยด้วยการเขียนแบบธรรมดาและการอ่านแบบระเหยได้ ... นี่เป็นสูตรสำหรับภัยพิบัติเนื่องจากอาจทำงานได้ในการตั้งค่าเดียว แต่ไม่ใช่แบบอื่น หากคุณกำลังมองหาซีแมนทิกส์แบบระเหยด้วยเธรดตัวเขียนเดี่ยวคุณสามารถใช้ AtomicReference.lazySet บนเธรดการเขียนและรับ () บนตัวอ่าน (ดูโพสต์นี้สำหรับการอภิปรายในหัวข้อ) ระเหยอ่านจะค่อนข้างถูก แต่ไม่ฟรีดูที่นี่
Nitsan Wakart

"... คุณสามารถใช้ putObjectVolatile เมื่อเขียนมัน ... " ฉันไม่ได้แนะนำให้เขียนแบบธรรมดา
Matt Crinklaw-Vogt

1

คุณต้องการถ้าคุณต้องการแทนที่ฟังก์ชั่นที่จัดทำโดยหนึ่งในคลาสที่ใช้งานอยู่ในปัจจุบัน

นี้สามารถกำหนดเอง / เร็วขึ้น / กะทัดรัดมากขึ้นอนุกรม / deserialization บัฟเฟอร์เร็วขึ้น / ใหญ่ / ปรับขนาดได้รุ่น ByteBuffer หรือเพิ่มตัวแปรอะตอมเช่นหนึ่งไม่สนับสนุนในปัจจุบัน

ฉันได้ใช้มันทั้งหมดนี้ในบางครั้ง



0

วัตถุดูเหมือนว่าจะมีความพร้อมในการทำงานในระดับต่ำกว่าปกติที่โค้ด Java อนุญาต หากคุณกำลังเขียนโค้ดแอปพลิเคชันระดับสูงการจัดการหน่วยความจำ JVM ที่เป็นนามธรรมและการดำเนินการอื่น ๆ อยู่ห่างจากระดับรหัสเพื่อให้โปรแกรมง่ายขึ้น ด้วยการใช้ไลบรารี่ที่ไม่ปลอดภัยคุณจะสามารถทำการดำเนินการในระดับต่ำได้อย่างมีประสิทธิภาพซึ่งโดยทั่วไปจะทำเพื่อคุณ

ดังที่ woliveirajr ระบุว่า "random ()" ใช้ Unsafe เพื่อ seed เช่นเดียวกับการดำเนินการอื่น ๆ ที่จะใช้ฟังก์ชัน allocateMemory () ที่รวมอยู่ใน Unsafe

ในฐานะโปรแกรมเมอร์คุณอาจไม่ต้องไปใช้ห้องสมุดนี้ แต่การควบคุมอย่างเข้มงวดเกี่ยวกับองค์ประกอบระดับต่ำนั้นมีประโยชน์ (นั่นคือสาเหตุที่ยังมีแอสเซมบลีและ (ในระดับที่น้อยกว่า) รหัส C ลอยไปรอบ ๆ ในผลิตภัณฑ์หลัก)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.