2017-08-04 5 views
12

मैं कुछ शोध उद्देश्यों के लिए जावा वस्तुओं के वास्तविक पते को निकालना चाहता हूं। बस स्पष्ट होने के लिए, मैं वास्तव में ऑब्जेक्ट का 48 बिट वर्चुअल एड्रेस चाहता हूं, आईडी या हैशकोड या कोई अद्वितीय पहचानकर्ता नहीं, और मैं समझता हूं कि उन पते को जीसी द्वारा चारों ओर स्थानांतरित किया गया है। मैं stackoverflow से here या here जैसे अन्य पोस्ट पढ़ रहा हूं।जावा ऑब्जेक्ट निष्कर्षण और सत्यापन

निम्नलिखित के लिए मैं @Peter Lawrey -> Is there a way to get a reference address? विधि का उपयोग करता हूं। तो यह वर्ग arrayBaseOffset विधि के साथ Unsafe कक्षा का उपयोग करता है। मुझे उन तरीकों के बारे में अजीब बात यह है कि वे प्रत्येक रन (कम से कम मेरे कंप्यूटर पर) के लिए एक ही परिणाम देते हैं जो होने की संभावना नहीं है। सुरक्षा आवंटन के लिए स्मृति आवंटन को यादृच्छिक माना जाना चाहिए।

इसके अलावा, मैंने Pintools के साथ उन विधियों को सत्यापित करने का प्रयास किया जो इंटेल से उपकरण उपकरण है जिसे मैं रन के मेमोरी निशान निकालने के लिए उपयोग करता था। मेरी समस्या यह है कि मैं स्मृति पते प्राप्त करने के लिए उपर्युक्त तरीकों से दिए गए पते के साथ पिंटोल्स के स्मृति ट्रेस में जो कुछ देखता हूं उससे संबंधित नहीं हूं। दिए गए पते को मेरी स्मृति ट्रेस में कभी भी एक्सेस नहीं किया जाता है।

तो मैं सोच रहा हूं कि उन तरीकों से क्या लौटाया गया है और उन परिणामों को अन्य उपकरणों के विरुद्ध कैसे सत्यापित किया गया है।

कुछ जानकारी: मेरी ओएस एक उबंटू x86_64 है, मेरे JVM OpenJDK 64bits 1.8.0_131 है, pintools संस्करण v3.2

है ================ === बिग संपादित करें:

`import sun.misc.Unsafe; 
import java.lang.reflect.Field; 

public class HelloWorld { 

    public static void main(String[] args) throws Exception { 
    Unsafe unsafe = getUnsafeInstance(); 
    Integer i = new Integer(42); 
    long addr_fromArray; 
    long addr_fromObject; 

///////////////////////////////////// 
    Object[] objects = {i}; 
    long baseOffset = unsafe.arrayBaseOffset(Object[].class); 
    addr_fromArray = unsafe.getLong(objects, baseOffset); 

    long factor1 = 8;   
    long addr_withFactor = (unsafe.getInt(objects, baseOffset) & 0xFFFFFFFFL) * factor1; 

    ///////////////////////////////////// 
    class Pointer { 
     Object pointer; 
    } 

    Pointer pointer = new Pointer(); 
    pointer.pointer = i; 
    long offset =  unsafe.objectFieldOffset(Pointer.class.getDeclaredField("pointer")); 
    addr_fromObject = unsafe.getLong(pointer, offset); 


    System.out.println("Addr of i from Array : 0x" + Long.toHexString(addr_fromArray)); 
    System.out.println("Addr of i from Object : 0x" + Long.toHexString(addr_fromObject)); 

    System.out.println("Addr of i from factor1 : 0x" + Long.toHexString(addr_withFactor)); 

    System.out.println("!=1");//Launch the pintools instrumentation 
    for(int a= 0 ; a < 123 ;a++){ 
     i = 10; 
    } 
    System.out.println("!=1");//Stop the pintools instrumentation 
} 

private static Unsafe getUnsafeInstance() throws SecurityException, 
NoSuchFieldException, IllegalArgumentException, 
IllegalAccessException { 
    Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); 
    theUnsafeInstance.setAccessible(true); 
    return (Unsafe) theUnsafeInstance.get(Unsafe.class); 
    } 
}` 

मैं मैं करने के लिए सूचक मिलती है: मुझे लगता है कि मेरे सवाल का अच्छी तरह से नहीं डाल रहा है, इसलिए मुझे एक अधिक परमाणु उदाहरण मिलता है, यहाँ जावा है कि मैं विश्लेषण करने की कोशिश है स्टैक ओवरफ़्लो पर मैंने देखा है कि विभिन्न तरीकों से पूर्णांक। फिर मैं एक मनमाना समय के लिए एक लूप करता हूं ताकि मैं इसे अपने मेमोरी ट्रेस में पहचान सकूं (नोट: मैंने जांच की है कि इस कोड के भीतर कोई जीसी कॉल नहीं होती है)

जब पिनटॉल्स विशिष्ट "! = 1" मानक आउटपुट में लिखा है, यह शुरू होता है/उपकरण

रोक इंस्ट्रूमेंटेशन चरण के दौरान हर पहुँच पर, मैं इस कोड को निष्पादित करें:

VOID RecordAccess(VOID* ip, int id_thread , VOID * addr, int id) 
{ 
    PIN_GetLock(&lock, id_thread); 
    if(startInstru) 
    { 
     log1 << "Data accessed: " << addr << "\tThread:" << id_thread << endl; 
     nb_access++; 
     uint64_t dummy = reinterpret_cast<uint64_t>(addr); 
     if(accessPerAddr.count(dummy) == 0) 
      accessPerAddr.insert(pair<uint64_t,uint64_t>(dummy, 0)); 
     accessPerAddr[dummy]++; 
    } 
} 
इस pintools साथ

, मैं एक स्मृति का पता लगाने + पर कैसे एक आयतचित्र उत्पन्न कई बार प्रत्येक मेमोरी पते का उपयोग किया जाता है। नोट: प्रत्येक थ्रेड के उपकरण के लिए "follow_execv" विकल्प के साथ पिनटोल लॉन्च किया गया है।

1) मैं मुद्रित मैं किसी भी पते पर (या इस पते पर पास करने के लिए कोई पहुंच देखें):

2 समस्याएं देखें। मुझे पिंटोल्स पर भरोसा है क्योंकि मैंने पहले काफी उपयोग किया है लेकिन शायद पिंटोल्स सही पते को पुनः प्राप्त करने में सक्षम नहीं है।

2) मुझे 123 बार (या इसके करीब) तक कोई पता नहीं देखा जा रहा है। इसके लिए मेरे विचार यह है कि शायद JVM ऑप्टिमाइज़ेशन निष्पादित करता है क्योंकि यह देखता है कि निष्पादित कोड का कोई प्रभाव नहीं है, इसलिए यह इसे निष्पादित नहीं करता है। हालांकि, मैंने लूप के अंदर एक बेहतर जटिल निर्देश के बिना एक अधिक जटिल निर्देश (जिसे यादृच्छिक संख्या संग्रहित करने की तरह अनुकूलित नहीं किया जा सकता) के साथ प्रयास किया।

मुझे यहां दूसरे चरण में जीसी प्रभाव के बारे में ज्यादा परवाह नहीं है। मैं केवल अपने जावा ऐप से मूल पते निकालने में सक्षम होना चाहता हूं, मुझे यकीन है कि पिंटोल्स मुझे दे रहा है।

+0

आप अपने कोड –

+0

'मेमोरी आवंटन को सुरक्षा कारणों से यादृच्छिक माना जाना चाहिए।' क्या आपके पास जावा में वास्तव में ऐसा कोई संदर्भ है? इस कथन में सी में कुछ समझ है, जहां बफर ओवरफ़्लो कोड निष्पादन का परिणाम हो सकता है। –

+0

अगर यह मदद करता है तो कुछ कोड जोड़ा गया! –

उत्तर

3

तो जब मैं इस दौड़ को पिनटोल के साथ इस तरह की एक स्क्रिप्ट के साथ प्रयोग कर रहा हूं, तो यहां। मुझे उल्लिखित पते या आस-पास के पते पर किए गए किसी भी पहुंच को नहीं देखा गया है

मुझे लगता है कि आपको और जानकारी दी जानी चाहिए कि आप कैसे चलते हैं और आप क्या देखते हैं।

ऑब्जेक्ट लेआउट का पता लगाने के लिए आप http://openjdk.java.net/projects/code-tools/jol का उपयोग कर सकते हैं।

Before GC 
# WARNING: Unable to attach Serviceability Agent. Unable to attach even with escalated privileges: null 
ascending: 76d430c7850, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
descending: 76d430e4850, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
shuffled: 76d43101850, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 

After GC 
ascending: 6c782859856d88, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
descending: 6c78285e856eb8, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
shuffled: 6c782863856fe8, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 

After GC 2 
ascending: 6c7828570548a8, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
descending: 6c78285c0549d8, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
shuffled: 6c782861054b08, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 

Process finished with exit code 0 

इस उदाहरण http://hg.openjdk.java.net/code-tools/jol/file/018c0e12f70f/jol-samples/src/main/java/org/openjdk/jol/samples/JOLSample_21_Arrays.java आप परीक्षण कर सकते हैं जीसी सरणियों पर प्रभावित करता है के साथ:

import org.openjdk.jol.info.GraphLayout; 

import java.io.PrintWriter; 
import java.util.Arrays; 
import java.util.Collections; 
import java.util.SortedSet; 

public class OrderOfObjectsAfterGCMain2 { 
    public static void main(String... args) { 
    Double[] ascending = new Double[16]; 
    for (int i = 0; i < ascending.length; i++) 
     ascending[i] = (double) i; 

    Double[] descending = new Double[16]; 
    for (int i = descending.length - 1; i >= 0; i--) 
     descending[i] = (double) i; 

    Double[] shuffled = new Double[16]; 
    for (int i = 0; i < shuffled.length; i++) 
     shuffled[i] = (double) i; 
    Collections.shuffle(Arrays.asList(shuffled)); 

    System.out.println("Before GC"); 
    printAddresses("ascending", ascending); 
    printAddresses("descending", descending); 
    printAddresses("shuffled", shuffled); 

    System.gc(); 
    System.out.println("\nAfter GC"); 
    printAddresses("ascending", ascending); 
    printAddresses("descending", descending); 
    printAddresses("shuffled", shuffled); 

    System.gc(); 
    System.out.println("\nAfter GC 2"); 
    printAddresses("ascending", ascending); 
    printAddresses("descending", descending); 
    printAddresses("shuffled", shuffled); 

} 

public static void printAddresses(String label, Double[] array) { 
    PrintWriter pw = new PrintWriter(System.out, true); 
    pw.print(label + ": "); 
    // GraphLayout.parseInstance((Object) array).toPrintable() has more info 
    SortedSet<Long> addresses = GraphLayout.parseInstance((Object) array).addresses(); 
    Long first = addresses.first(), previous = first; 
    pw.print(Long.toHexString(first)); 
    for (Long address : addresses) { 
     if (address > first) { 
      pw.print(Long.toHexString(address - previous) + ", "); 
      previous = address; 
     } 
    } 
    pw.println(); 
} 
इस टूल से

मैं लगभग एक ही परिणाम है।

युपीडी

आप अधिक जानकारी प्रदान की है, मैं समय में आपकी सहायता करने की कोशिश की। सबसे पहले मेरी आँखों

for(int a= 0 ; a < 123 ;a++){ 
    i = 10; 
} 

जावा, बहुत चालाक इस चक्र को खत्म करने की है परिणाम हमेशा होता है के रूप में catched - एक अनुदेश "मैं = 10,"। उदाहरण के लिए,

import org.openjdk.jmh.annotations.Benchmark; 
import org.openjdk.jmh.annotations.OperationsPerInvocation; 
import org.openjdk.jmh.annotations.Scope; 
import org.openjdk.jmh.annotations.State; 
import org.openjdk.jmh.infra.Blackhole; 
import org.openjdk.jmh.runner.Runner; 
import org.openjdk.jmh.runner.options.OptionsBuilder; 

@State(Scope.Benchmark) 
public class TestLoop { 

    static final int _123 = 123; 
    int TEN = 10; 

    @Benchmark 
    @OperationsPerInvocation(_123) 
    public void oneAssigment() { 
     Integer i = 1; 
     i = 10; 
    } 

    @Benchmark 
    @OperationsPerInvocation(_123) 
    public Integer oneAssigmentAndReturn() { 
     Integer i = 1; 
     i = TEN; 
     return i; 
    } 

    @Benchmark 
    @OperationsPerInvocation(_123) 
    public void doWrong() { 
     Integer i = 1; 
     for (int a = 0; a < _123; a++) { 
      i = 10; 
     } 
    } 

    @Benchmark 
    @OperationsPerInvocation(_123) 
    public void doWrongWithLocalVariable() { 
     Integer i = -1; 
     for (int a = 0; a < _123; a++) { 
      i = TEN; 
     } 
    } 

    @Benchmark 
    @OperationsPerInvocation(_123) 
    public Integer doWrongWithResultButOneAssignment() { 
     Integer i = -1; 
     for (int a = 0; a < _123; a++) { 
      i = TEN; 
     } 
     return i; 
    } 

    @Benchmark 
    @OperationsPerInvocation(_123) 
    public void doWrongWithConstant(Blackhole blackhole) { 
     for (int a = 0; a < _123; a++) { 
      blackhole.consume(10); 
     } 
    } 

    @Benchmark 
    @OperationsPerInvocation(_123) 
    public void doRight(Blackhole blackhole) { 
     for (int a = 0; a < _123; a++) { 
      blackhole.consume(TEN); 
     } 
    } 

    public static void main(String[] args) throws Exception { 
     new Runner(
       new OptionsBuilder() 
         .include(TestLoop.class.getSimpleName()) 
         .warmupIterations(10) 
         .measurementIterations(5) 
         .build() 
     ).run(); 
    } 


} 

प्रदान करेंगे

Benchmark         Mode Cnt    Score   Error Units 
TestLoop.doRight       thrpt 50  352484417,380 ± 7015412,429 ops/s 
TestLoop.doWrong       thrpt 50 358755522786,236 ± 5981089062,678 ops/s 
TestLoop.doWrongWithConstant    thrpt 50  345064502,382 ± 6416086,124 ops/s 
TestLoop.doWrongWithLocalVariable   thrpt 50 179358318061,773 ± 1275564518,588 ops/s 
TestLoop.doWrongWithResultButOneAssignment thrpt 50 28834168374,113 ± 458790505,730 ops/s 
TestLoop.oneAssigment      thrpt 50 352690179375,361 ± 6597380579,764 ops/s 
TestLoop.oneAssigmentAndReturn    thrpt 50 25893961080,851 ± 853274666,167 ops/s 

आप देख सकते हैं, अपने विधि एक काम के समान है। यह भी देखें:

+0

क्षमा करें, आपके उत्तर के साथ, मुझे एहसास हुआ कि मैं पूरी तरह स्पष्ट नहीं था, इसलिए मैंने अपनी पोस्ट संपादित की, आपके उत्तर के लिए धन्यवाद। यह देखना अच्छा होता है कि इन विधियों को अन्य उपकरणों के खिलाफ पुष्टि की गई है।शायद, पिंटोल्स जावा ऐप्स के साथ ठीक से काम नहीं कर रहा है और सही पते को पुनर्प्राप्त करने में सक्षम नहीं है –

+0

ग्रेगोरी वाउमोरिन मैं आपके अपडेटेड पोस्ट के माध्यम से चला गया और जानकारी जोड़ता हूं। – egorlitvinenko

संबंधित मुद्दे