从套接字接收大文件导致内存泛滥,是否存在内存泄漏?
Receiving a big file from socket floods memory, do I have a memory leak?
我想将一个大文件从一台机器发送到另一台机器。所有字节发送成功,另一端也接收到,但操作大量命中接收端的内存。内存使用率在几秒钟内以每秒约 400MB 的速度上升,然后稳定下来。我测试的文件大小约为 7 GB。
这是我用来从套接字读入文件的代码:
size_t recv_file(int socket, std::filesystem::path& dest_file) {
uint64_t bytes_to_read = recv_byte_count(socket);
char* const file_buffer = new char[MAX_BUFFER_FILE];
size_t total_received{ 0 };
try {
std::fstream fs;
fs.open(dest_file, std::fstream::in | std::fstream::out | std::fstream::app);
while (bytes_to_read > 0) {
const unsigned int actual_bytes_to_read = (bytes_to_read > MAX_BUFFER_FILE) ? MAX_BUFFER_FILE : bytes_to_read;
size_t received = recv_raw(socket, file_buffer, actual_bytes_to_read, MAX_BUFFER_FILE);
if (received > 0) {
fs.write(file_buffer, received);
bytes_to_read -= received;
total_received += received;
std::cout << "Bytes received: " << total_received << std::endl;
memset(file_buffer, 0, MAX_BUFFER_FILE);
} else throw WSA_socket_exception(WSAGetLastError(), socket);
}
fs.close();
delete[] file_buffer;
}
catch (...) {
delete[] file_buffer;
return 0;
}
return total_received;
}
size_t recv_raw(const int socket, void* buffer, size_t bytes_to_read, int buffer_size = MAX_BUFFER) {
char* ptr = static_cast<char*>(buffer);
size_t received_total{ 0 };
while (bytes_to_read > 0) {
const int actual_bytes_to_read{ std::min(buffer_size, static_cast<int>(bytes_to_read)) };
const int received = recv(socket, ptr, actual_bytes_to_read, 0);
if (received == 0 || received < -1) throw connection_close_exception(socket);
if (received > 0) {
bytes_to_read -= static_cast<size_t>(received);
ptr += received;
received_total += static_cast<size_t>(received);
}
}
return received_total;
}
数据从接收到最终写入文件的过程中被复制了很多次。
tcp 和文件都可能分配许多临时缓冲区,等待 received 被调用或文件(部分)刷新到文件系统。 Tcp 由您的 tcp 设置控制,定义了它可以分配多少,fs 中可能有类似的设置,否则您可以通过滚动 std::streambuf.[=10= 的自己的子 class 来滚动自己的]
我想将一个大文件从一台机器发送到另一台机器。所有字节发送成功,另一端也接收到,但操作大量命中接收端的内存。内存使用率在几秒钟内以每秒约 400MB 的速度上升,然后稳定下来。我测试的文件大小约为 7 GB。
这是我用来从套接字读入文件的代码:
size_t recv_file(int socket, std::filesystem::path& dest_file) {
uint64_t bytes_to_read = recv_byte_count(socket);
char* const file_buffer = new char[MAX_BUFFER_FILE];
size_t total_received{ 0 };
try {
std::fstream fs;
fs.open(dest_file, std::fstream::in | std::fstream::out | std::fstream::app);
while (bytes_to_read > 0) {
const unsigned int actual_bytes_to_read = (bytes_to_read > MAX_BUFFER_FILE) ? MAX_BUFFER_FILE : bytes_to_read;
size_t received = recv_raw(socket, file_buffer, actual_bytes_to_read, MAX_BUFFER_FILE);
if (received > 0) {
fs.write(file_buffer, received);
bytes_to_read -= received;
total_received += received;
std::cout << "Bytes received: " << total_received << std::endl;
memset(file_buffer, 0, MAX_BUFFER_FILE);
} else throw WSA_socket_exception(WSAGetLastError(), socket);
}
fs.close();
delete[] file_buffer;
}
catch (...) {
delete[] file_buffer;
return 0;
}
return total_received;
}
size_t recv_raw(const int socket, void* buffer, size_t bytes_to_read, int buffer_size = MAX_BUFFER) {
char* ptr = static_cast<char*>(buffer);
size_t received_total{ 0 };
while (bytes_to_read > 0) {
const int actual_bytes_to_read{ std::min(buffer_size, static_cast<int>(bytes_to_read)) };
const int received = recv(socket, ptr, actual_bytes_to_read, 0);
if (received == 0 || received < -1) throw connection_close_exception(socket);
if (received > 0) {
bytes_to_read -= static_cast<size_t>(received);
ptr += received;
received_total += static_cast<size_t>(received);
}
}
return received_total;
}
数据从接收到最终写入文件的过程中被复制了很多次。
tcp 和文件都可能分配许多临时缓冲区,等待 received 被调用或文件(部分)刷新到文件系统。 Tcp 由您的 tcp 设置控制,定义了它可以分配多少,fs 中可能有类似的设置,否则您可以通过滚动 std::streambuf.[=10= 的自己的子 class 来滚动自己的]