4

Following a previous question of mine, and Some Name's response , I would like to try the opposite way and enhance the previous question:

I would like to do the following steps:

  1. Allocate buffer in Java
  2. Fill the array in C++
  3. Edit the values in Java
  4. Do some number crunching in C++
  5. Read the values in Java

Consider the following class in C++:

#pragma once
#pragma pack(push, 8)
class Point
{

public:
    double x;
    double y;
    Point();
    virtual ~Point();

    void ebeProduct(Point &other) {
        x = x * other.x;
        y = y * other.y;
    }
};



Point::Point()
{
}


Point::~Point()
{
}

#pragma pack(pop)

The following code snippet:

Point point = Point();
std::cout << "Size of Point: " << sizeof(Point) << std::endl;
std::cout << "Address is: " << &point << std::endl;
std::cout << "x address is: " << &(point.x) << " and offset is: " << (long long)&(point.x) - (long long)&point << std::endl;
std::cout << "y address is: " << &(point.y) << " and offset is: " << (long long)&(point.y) - (long long)&point << std::endl;

shows the following result:

Size of Point: 24
Address is: 000000D45B0FF2C0
x address is: 000000D45B0FF2C8 and offset is: 8
y address is: 000000D45B0FF2D0 and offset is: 16

So now I can assume the following sizes in Java:

final int NUMBER_OF_POINTS = 10;
final int SIZE_OF_POINT = 24;
final int X_OFFSET = 8;
final int Y_OFFSET = 16;

Next, I will allocate a memory region using unsafe and call public static native void allocatePoints(long address, int numberOfPoints); In order to fill them with Point objects:

long address = unsafe.allocateMemory(NUMBER_OF_POINTS * SIZE_OF_POINT);
allocatePoints(address, NUMBER_OF_POINTS);

The C++ code that fills the points:

Point * points = (Point *) address;
for (int pointIndex = 0; pointIndex < numberOfPoints; pointIndex++) {
    new(points + pointIndex) Point();
}

Next, I will fill the points in Java with arbitrary numbers, base on the given offsets:

for (int i = 0; i < NUMBER_OF_POINTS; i++) {
  unsafe.putDouble(address + i * SIZE_OF_POINT + X_OFFSET, i);
  unsafe.putDouble(address + i * SIZE_OF_POINT + Y_OFFSET, i * 2);
}

Next, calling public static native void multiplyPoints(); which only ebe products each second point with the one before it.

Finally, I will print the given values in Java:

for (int i = 0; i < NUMBER_OF_POINTS; i++) {
  System.err.print(unsafe.getDouble(address + i * SIZE_OF_POINT + X_OFFSET));
  System.err.print(" ; ");
  System.err.println(unsafe.getDouble(address + i * SIZE_OF_POINT + Y_OFFSET));
}

These stages actually prints correct results.
My question is if these stages are reasonable: Can I assume that the given offsets are correct (on the same machine for now), and that writing the values directly into the buffer in Java, and reading them from the objects in C++, will always yield correct results?

1 Answer 1

1

I see three potential pitfalls in general:

  1. Padding and vtables inside Point might mess up the size: The C++ compiler might decide to align members of Point up to their desired alignment (for example a double wants 8-byte alignment, while char does not specify any alignment.)

    Likewise, if your C++ objects contain any virtual methods (as your example does), your object will have a vtable at the front. You need to take this into account when allocating memory and accessing individual members.

  2. Alignment of Point might mess up the stride of your array: Assume the last element of your class had an extra char, then the next element will be aligned to the nearest multiple of 8 bytes. (in other words, your array stride would be 8+8+1 (data) +7 bytes padding)

    You need to take this into account when both allocating memory and accessing individual members.

  3. sun.misc.Unsafe is on its way out. This code might eventually stop working in JDK11 and up.

Sign up to request clarification or add additional context in comments.

1 Comment

1+2: Regarding the alignment: I am using the #pragma pack(16) directive which should guarantee that everything will be aligned. 3: If Unsafe will be deprecated, and there won't be any other way to allocate large chunks of memory, I will use ByteBuffer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.