php / php/php-src

Unserialized objects use significantly more memory than ones created with the normal constructor

Đang mở
#10,126 6 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Bug Category: Engine Category: Serialization Extension: standard Status: Needs Triage
Ngôn ngữ chính
C
Star
40.4k
Fork
8.2k
Merge trung bình
2 ngày 15 giờ
Pull request đã merge (30 ngày)
103

Mô tả

Description

Consider the following code:

class SomeClass {
    public $a = 1;
    public $b = 2;
    public $c = 3;
    public $d = 4;
    public $e = 5;
    public $f = 6;
}

$s1 = serialize(new SomeClass());

function new_object() {
    return new SomeClass();
}

function unserialize_object() {
    global $s1;
    return unserialize($s1);
}


class OtherClass {
    public $a = 1;
    public $b = 2;
    public $c = 3;
    public $d = 4;
    public $e = 5;
    public $f = 6;
    
    public function __unserialize(array $attrs) {
        foreach ($attrs as $name => $value) 
            $this->$name = $value;
    }
}

$s2 = serialize(new OtherClass());

function new_object_other() {
    return new OtherClass();
}

function unserialize_object_other() {
    global $s2;
    return unserialize($s2);
}


foreach ([
    'new_object', 'unserialize_object',
    'new_object_other', 'unserialize_object_other',
] as $f) {
    $arr = [];
    for ($i = 0; $i < 50000; ++$i) {
        $arr[] = $f();
    }

    echo $f, " ", memory_get_usage() >> 20, "\n";
}

SomeClass contains some data. new_object() will create an instance, while unserialize_object() will unserialize an instance of exactly the same state (see $s1). When an array of 50k elements is created with one or another, the output for memory usage is as follows:

new_object 10
unserialize_object 43

I.e. the 50k instances created with the constructor use 10M memory, while the unserialized ones 43M. It seems that some data structures that are used while unserializing are not freed. However, when unsetting $arr to destroy the instances, memory consumption will drop to 1M, as expected.

Now consider OtherClass which has the __unserialize method. Nothing fancy, it just sets the attributes as the default handler would do. new_object_other() and unserialize_object_other() replicate the same logic as explained above, but for the new class. Output in this case is

new_object_other 10
unserialize_object_other 10

That is, memory consumption is the same regardless of how the objects are created.

Surplus memory usage grows with the number of attributes.

Tested with 8.1.2 and 8.2.0. Can also be seen on https://3v4l.org/ .

PHP Version

8.2.0

Operating System

No response

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu bằng cách chạy tập lệnh PHP được cung cấp và so sánh memory_get_usage() cho new_object(), unserialize_object() và biến thể __unserialize() trên 50.000 đối tượng. Truy vết các đường đi serialize()/unserialize() liên quan đến reproducer. Hoàn thành có nghĩa là các đối tượng tương đương được unserialize theo mặc định không còn giữ lại nhiều bộ nhớ hơn đáng kể so với các đối tượng được tạo theo cách thông thường.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
php
Lĩnh vực
backend
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.