Xpoint
   [напомнить пароль]

Обнуляется ли ByteBuffer при создании?

Метки: [без меток]
2006-10-10 23:12:19 [обр] Даниэль Алиевский(35/125)[досье]

Все объекты Java, равно как и массивы, при создании заполняются нулями (false для boolean, null для ссылок). Довольно фундаментальное свойство языка, описанное во множестве учебников. Весьма ценное свойство для гарантии одинаковой работы программы независимо от условий.

А вот что насчет java.nio.ByteBuffer? Как-то сходу не получилось найти информацию - будет ли обнулен ByteBuffer, созданный при помощи методов allocate или allocateDirect. Вообще-то сие важно: ведь эксперименты здесь совершенно ничего не доказывают (хотя, конечно, в тесте получаются нули). Вдруг на Windows все в порядке, а на какой-нибудь Unix окажется не так? Тут нужен четко прописанный контракт класса, или пакета, или часть спецификации языка.

Кто-нибудь может что-нибудь подсказать? Буду благодарен.

спустя 12 часов [обр] GRAy(14/259)[досье]
Декомпиляция нам в помощь ;)
При вызове allocateDirect происходит создание экземпляра DirectByteBuffer, а при вызове allocate - экземпляра HeapByteBuffer. Во втором случае для хранения буферных байтиков используется обычный массив и никаких различий от платформы к платформе быть не должно. В первом же случае используется внутренний класс Bits для выделения памяти средствами операционной системы и никаких процедур заполнения выделенной области памяти нулями я не обнаружил, возможно это происходит где-то внутри реализации native методов класса Unsafe.
спустя 5 часов [обр] Даниэль Алиевский(35/125)[досье]

Я ведь не спрашиваю, как оно работает на самом деле. Это нетрудно проследить. Я спрашиваю, как оно обязано работать на всех платформах. Обычно sun-овцы довольно аккуратны: если некое важное утверждение верно всегда, они про это пишут, если же они не гарантируют соответствующего поведения, они про это тоже пишут. Но в данном случае я пока не нашел нужных спецификаций.

Собственно, я пишу универсальную библиотеку работы с векторами (массивами переменного размера), где ByteBuffer - один из возможных методов хранения вектора, наряду с обычным массивом, дисковым файлом и некоторыми более экзотическими вариантами. Я документирую, что при создании или увеличении размера вектора он автоматически оказывается заполнен нулями. И мне как-то не нравится, что пока я вынужден вручную обнулять только что созданный ByteBuffer (не имея гарантии, что он изначально обнулен). Если Java сама заботится, чтобы вновь созданный гигабайтный байтовый буфер был обнулен, лучше бы об этом явно заявить - повторное зануление может удвоить время дискового свопинга.

спустя 38 минут [обр] GRAy(14/259)[досье]

Buffer

The initial content of a buffer is, in general, undefined.

Вы это хотели увидеть?

спустя 56 минут [обр] Даниэль Алиевский(35/125)[досье]

Да, может быть! Но, гм, подобный комментарий при описании инвариантов можно понять как угодно... В конце концов, ByteBuffer можно смапировать на файл, и при этом он, разумеется, не будет заполнен нулями.

Вот кабы подобный комментарий был к методу allocateDirect, это было бы однозначно. А так я что-то не уверен. Ведь они реально зачем-то обнуляют DirectByteBuffer. Или Вы хотите сказать, что такое обнуление - случайность или проявление некой особенности OS Windows?

спустя 1 час 26 минут [обр] GRAy(14/259)[досье]
Даниэль Алиевский[досье] Я хочу сказать ;) что они умыли руки изначально. А как реализован конкретно DirectByteBuffer - "проблемы индейцев". Если вам удасться разжиться исходными кодами класса Unsafe, вернее даже кодами подлежащей native библиотеки вы с некоторой долей уверенности сможете сказать что таки да, там гарантированы нули, или таки нет, нули там не гарантированы (опять же для одной конкретной платформы). Я думаю имеет смысл смотреть в сторону стандартов типа POSIX и их рекомендаций по поводу функций выделения памяти.
спустя 14 часов [обр] Даниэль Алиевский(35/125)[досье]

Все-таки до конца вы меня не убедили. Умыли руки так умыли, их право, но кто ж так умывается :) Могли бы четко, "громкими буквами" написать в комментарии к allocateDirect, что содержимое созданного буфера может быть любым. А в комментарии к allocate, наоборот, написать, что содержимое будет нулевым - ведь это следствие использования стандартной Java-кучи. Более того, на нижнем native-уровне как раз проще создать неинициализированный буфер, а вот занулять его приходится специально. Зачем же они это делают, если, как вы предполагаете, их документация не требует обнуления? Ведь это время, причем немаленькое - особенно для больших буферов, на которые (вроде бы) и рассчитан ByteBuffer. Если массив хоть немного не помещается в имеющуюся RAM, то начинается свопинг, и общее время работы алгоритмов становится пропорционально числу проходов по массиву - даже если это банальное обнуление.

Вот такой простенький тест показывает, что native-код действительно тратит время на создание direct-буфера, пропорциональное его длине, и что в конце и правда нули:

import java.nio.*;

public class T {
    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);
        long t1 = System.nanoTime();
        ByteBuffer bb = ByteBuffer.allocateDirect(n);
        long t2 = System.nanoTime();
        System.out.println((t2-t1+0.0)/n);
        for (int k = 0; k < 100; k++) System.out.print(bb.get(bb.limit()-1-k) + " ");
    }
}

Стало быть, зачем-то они его обнуляют. Может быть, все же где-то в спецификации языка или подобном документе затесалась фраза, что все вновь созданные объекты, включая результат allocateDirect, заполнены нулями?

Powered by POEM™ Engine Copyright © 2002-2005