我们是否必须手动释放分配的ByteBuffer?

时间:2019-03-29 12:56:50

标签: java lwjgl nio

我正在写一些使用ByteBuffer的东西。 docs of the API中说

  

没有办法显式释放缓冲区(没有特定于JVM的缓冲区)   反射)。 缓冲区对象要接受GC ,通常需要两个   缓冲区对象变为后,GC循环释放堆外内存   无法访问。

但是我在SO post's accepted answer中阅读

  

BigMemory通过直接使用JVM进程的内存地址空间   与其他本机Java不同,不受GC 约束的字节缓冲区   对象。

现在我该怎么办,我应该释放创建的缓冲区吗?还是我误会了文档或答案中的某些内容?

2 个答案:

答案 0 :(得分:1)

这取决于您如何创建缓冲区,有许多可能的用例。常规ByteBuffer.allocate()将在堆上创建,并由GC收集。其他选项,例如本机内存可能不会。

Terracotta BigMemory是一种本机堆外内存,不受JVM GC的控制。如果您在这种类型的内存中分配缓冲区,则必须自己清除它。

清除缓冲区是个好主意,即使缓冲区已分配在堆内存中也是如此。 GC将负责收集未使用的缓冲区,但这将需要一些时间。

答案 1 :(得分:1)

LWJGL中BufferUtils的文档也说:没有办法明确免费 ByteBuffer

使用标准机制分配的ByteBuffer对象(即,通过直接或间接调用ByteBuffer#allocateDirect)将受到GC的约束,并将最终清除。

您链接的答案似乎特别是指 BigMemory 库。使用JNI,您可以创建一个(直接)ByteBffer,该ByteBuffer由GC处理,并且由您决定实际释放基础数据的位置。


但是,一个简短的建议:在处理LWJGL和其他依赖(直接)ByteBuffer对象的库以将数据传输到本机端时,您应该考虑这些缓冲区的使用模式。特别是对于OpenGL绑定库,您经常需要float,该空间只能容纳16个class Renderer { void renderMethodThatIsCalledThousandsOfTimesPerSecond() { ByteBuffer bb = ByteBuffer.allocateDirect(16 * 4); fill(bb); passToOpenGL(bb); } } 值(例如,包含要发送到OpenGL的矩阵)。在许多情况下,使用这些缓冲区进行数据传输的方法将被频繁地称为

在这种情况下,反复分配这些小的,短暂的缓冲区通常不是一个好主意:

class Renderer {

    private final ByteBuffer MATRIX_BUFFER_4x4 = ByteBuffer.allocateDirect(16 * 4);

    void renderMethodThatIsCalledThousandsOfTimesPerSecond() {
        fill(MATRIX_BUFFER_4x4);
        passToOpenGL(MATRIX_BUFFER_4x4);
    }
}

创建这些缓冲区和GC会大大降低性能-并以GC暂停的形式令人不安,这可能会导致游戏延迟。

在这种情况下,提取分配并重新使用缓冲区可能是有益的:

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neural_network import MLPRegressor
import numpy as np
from sklearn.model_selection import cross_validate

# Generate some random data
X = np.random.rand(100,5)
Y = np.dot(X, np.random.rand(5))+np.random.rand(100)

# Split into train and test
X_train, X_test, y_train, y_test = train_test_split(X, Y)

# Use 4 fold cross validation on train data
cv_results = cross_validate(MLPRegressor(hidden_layer_sizes=(10,10)), X_train, y_train, cv=4, 
                            scoring=('neg_mean_squared_error'), return_estimator=True)
print (cv_results['test_score'])

# Make predictions on test data
y = np.zeros(len(y_test))
for i, model in enumerate(cv_results['estimator']):
    y_hat = model.predict(X_test)
    print ("Model {0} MSE Error: {1}".format(i, 
        mean_squared_error(y_test, y_hat)))
    y += y_hat

print ("Average Test MSE Error: {0}".format(
        mean_squared_error(y_test, y/len(models))))