لماذا أحصل على "غير كافية التخزين المتاحة لمعالجة هذا الأمر" باستخدام جافا MappedByteBuffers?

StackOverflow https://stackoverflow.com/questions/1927123

  •  20-09-2019
  •  | 
  •  

سؤال

لدي مجموعة كبيرة جدا من زوجي أن أنا باستخدام القرص المستندة إلى ملف ترحيل الصفحات قائمة MappedByteBuffers التعامل معها ، انظر هذا السؤال لمزيد من الخلفية.أنا على التوالي على ويندوز XP باستخدام جافا 1.5.

هنا هو جزء رئيسي من التعليمات البرمجية التي لا تخصيص المخازن المؤقتة ضد الملف...

try 
{
 // create a random access file and size it so it can hold all our data = the extent x the size of a double
 f = new File(_base_filename);
 _filename = f.getAbsolutePath();
 _ioFile = new RandomAccessFile(f, "rw");
 _ioFile.setLength(_extent * BLOCK_SIZE);
    _ioChannel = _ioFile.getChannel();

    // make enough MappedByteBuffers to handle the whole lot
 _pagesize = bytes_extent;
 long pages = 1;
 long diff = 0;
 while (_pagesize > MAX_PAGE_SIZE)
 {
  _pagesize  /= PAGE_DIVISION;
  pages *= PAGE_DIVISION;

  // make sure we are at double boundaries.  We cannot have a double spanning pages
  diff = _pagesize  % BLOCK_SIZE;
  if (diff != 0) _pagesize  -= diff;

 }

 // what is the difference between the total bytes associated with all the pages and the
 // total overall bytes?  There is a good chance we'll have a few left over because of the
 // rounding down that happens when the page size is halved
 diff = bytes_extent - (_pagesize  * pages);
 if (diff > 0)
 {
  // check whether adding on the remainder to the last page will tip it over the max size
  // if not then we just need to allocate the remainder to the final page
  if (_pagesize  + diff > MAX_PAGE_SIZE)
  {
   // need one more page
   pages++;
  }
 }

 // make the byte buffers and put them on the list
 int size = (int) _pagesize ;  // safe cast because of the loop which drops maxsize below Integer.MAX_INT
 int offset = 0;
 for (int page = 0; page < pages; page++)
 {
  offset = (int) (page * _pagesize );

  // the last page should be just big enough to accommodate any left over odd bytes
  if ((bytes_extent - offset) < _pagesize )
  {
   size = (int) (bytes_extent - offset);
  }

  // map the buffer to the right place 
     MappedByteBuffer buf = _ioChannel.map(FileChannel.MapMode.READ_WRITE, offset, size);

     // stick the buffer on the list
     _bufs.add(buf);
 }

 Controller.g_Logger.info("Created memory map file :" + _filename);
 Controller.g_Logger.info("Using " + _bufs.size() + " MappedByteBuffers");
    _ioChannel.close();
    _ioFile.close(); 
} 
catch (Exception e) 
{
 Controller.g_Logger.error("Error opening memory map file: " + _base_filename);
 Controller.g_Logger.error("Error creating memory map file: " + e.getMessage());
 e.printStackTrace();
 Clear();
    if (_ioChannel != null) _ioChannel.close();
    if (_ioFile != null) _ioFile.close();
 if (f != null) f.delete();
 throw e;
} 

أحصل على الخطأ المذكورة في العنوان بعد تخصيص الثاني أو الثالث العازلة.

اعتقدت أنه كان على علاقة الذاكرة القريبة المتاحة ، لذلك حاولت ذلك مع أحجام مختلفة وأرقام الصفحات ، ولكن دون فائدة ممكنة.

ماذا بالضبط "غير كافية التخزين المتاحة لمعالجة هذا الأمر" يعني ما إذا كان هناك أي شيء يمكنني القيام به حيال ذلك ؟

اعتقد ان نقطة MappedByteBuffers كانت القدرة على أن تكون قادرة على التعامل مع هياكل أكبر مما كنت يمكن أن يصلح على كومة ، ويعاملهم كما لو كانوا في الذاكرة.

أي أدلة ؟

تحرير:

ردا على إجابة أدناه (@adsk) غيرت رمز لذا لم يكن أكثر من واحدة نشطة MappedByteBuffer في أي وقت واحد.عندما أود أن أشير إلى المنطقة الملف حاليا تفاصيلها أنا غير المرغوب فيه الخريطة الحالية وإنشاء واحدة جديدة.أنا لا يزال الحصول على نفس الخطأ بعد حوالي 3 خريطة العمليات.

علة نقلت مع GC لا جمع MappedByteBuffers لا يزال يبدو أن المشكلة في JDK 1.5.

هل كانت مفيدة؟

المحلول

اعتقد ان نقطة MappedByteBuffers كانت القدرة على أن تكون قادرة على التعامل مع هياكل أكبر مما كنت يمكن أن يصلح على كومة ، ويعاملهم كما لو كانوا في الذاكرة.

لا.الفكرة / أن تسمح لك لمعالجة أكثر من 2**31 الزوجي ...على افتراض أن لديك ذاكرة كافية ، وتم استخدام 64 بت JVM.

(أنا على افتراض أن هذه هي المرة السؤال هذا السؤال.)

تحرير:بوضوح, هناك حاجة إلى مزيد شرح.

هناك عدد من القيود التي تأتي في اللعب.

  1. جافا الأساسية القيد الذي length سمة من مجموعة و مجموعة فهارس نوع int.هذا جنبا إلى جنب مع حقيقة أن int وقعت مجموعة لا يمكن أن يكون سلبي الحجم يعني أن أكبر مجموعة ممكنة يمكن أن يكون 2**31 عناصر.وينطبق هذا الحظر على 32bit و 64bit JVMs.بل هو جزء أساسي من لغة جافا ...مثل حقيقة أن char القيم من 0 إلى 65535.

  2. باستخدام 32 بت JVM يضع (النظرية) الحد الأعلى من 2**32 على عدد وحدات البايت التي يتم عنونة قبل JVM.وهذا يشمل كامل كومة التعليمات البرمجية الخاصة بك ، مكتبة الفئات التي تستخدمها ، JVM الأم رمز النواة الذاكرة المستخدمة في تعيين مخازن ...كل شيء.(في الواقع ، اعتمادا على النظام الأساسي الخاص بك, نظام التشغيل قد تعطيك أقل بكثير من 2**32 بايت إذا مساحة العنوان.)

  3. المعلمات التي تعطيها على سطر الأوامر جافا تحديد مقدار ذاكرة كومة الذاكرة المؤقتة JVM سوف تسمح التطبيق الخاص بك لاستخدام.تعيين الذاكرة باستخدام MappedByteBuffer كائنات لا تعول نحو هذا.

  4. مقدار الذاكرة أن نظام التشغيل سوف تعطيك يعتمد (على لينكس/يونكس) على إجمالي مساحة المبادلة تكوين 'عملية' حدود وهلم جرا.حدود مماثلة ربما تنطبق على ويندوز.و بالطبع يمكنك فقط تشغيل 64bit JVM إذا كان المضيف هو نظام التشغيل 64bit قادرة وكنت تستخدم 64 بت قادرة على الأجهزة.(إذا كان لديك جهاز بنتيوم, كنت عادي من الحظ.)

  5. أخيرا, مقدار الذاكرة الفعلية في النظام الخاص بك يأتي دور.من الناحية النظرية ، يمكنك أن تطلب JVM استخدام كومة ، وما إلى ذلك عدة مرات أكبر من الجهاز من الذاكرة الفعلية.في الواقع, هذا هو فكرة سيئة.إذا كنت على تخصيص الذاكرة الظاهرية النظام الخاص بك سوف يسحق و أداء التطبيق سوف تذهب من خلال الكلمة.

اتخاذ بعيدا هو هذا:

  • إذا كنت تستخدم 32 بت JVM ، ربما تقتصر على ما بين 2**31 و 2**32 بايت من الذاكرة عنونة.هذه مساحة كافية لمدة أقصاها بين 2**29 و 2**30 الزوجي ، ما إذا كان يمكنك استخدام صفيف أو تعيين العازلة.

  • إذا كنت تستخدم 64 بت JVM ، يمكن أن تمثل واحدة من مجموعة من 2**31 الزوجي.الحد النظري المعينة العازلة سيكون 2**63 بايت أو 2**61 الزوجي ، ولكن الحد العملي سيكون تقريبا مقدار الذاكرة الفعلية الجهاز الخاص بك.

نصائح أخرى

عند تعيين ذاكرة ملف ، فمن الممكن أن ينفد من مساحة عنوان في 32 بت VM.يحدث هذا حتى إذا كان الملف هو تعيينها في قطع صغيرة و تلك ByteBuffers لم تعد قابلة للوصول.والسبب هو أن GC أبدا في ركلات الحرة المخازن المؤقتة.

الرجوع الخلل في http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6417205

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top