Bạn không thể tính toán ngược lại dấu chân chính xác của một biến vì hai biến có thể chia sẻ cùng một không gian được cấp phát trong bộ nhớ
Hãy thử chia sẻ bộ nhớ giữa hai mảng, chúng ta thấy rằng việc phân bổ mảng thứ hai tốn một nửa bộ nhớ của mảng đầu tiên. Khi chúng ta bỏ đặt cái đầu tiên, gần như tất cả bộ nhớ vẫn được cái thứ hai sử dụng.
echo memory_get_usage()."\n"; // <-- 433200
$c=range(1,100);
echo memory_get_usage()."\n"; // <-- 444348 (+11148)
$d=array_slice($c, 1);
echo memory_get_usage()."\n"; // <-- 451040 (+6692)
unset($c);
echo memory_get_usage()."\n"; // <-- 444232 (-6808)
unset($d);
echo memory_get_usage()."\n"; // <-- 433200 (-11032)
Vì vậy, chúng ta không thể kết luận rằng mảng thứ hai sử dụng một nửa bộ nhớ, vì nó sẽ trở thành sai khi chúng ta hủy đặt mảng đầu tiên.
Để có cái nhìn đầy đủ về cách bộ nhớ được cấp phát trong PHP và cho mục đích sử dụng, tôi khuyên bạn nên đọc bài viết sau: Các mảng (và giá trị) trong PHP thực sự lớn như thế nào? (Gợi ý: LỚN!)
Kiến thức cơ bản về đếm tham chiếu trong tài liệu PHP cũng có rất nhiều thông tin về việc sử dụng bộ nhớ, và tài liệu tham khảo đếm đến phân đoạn dữ liệu được chia sẻ.
Các giải pháp khác nhau được đưa ra ở đây là tốt cho các phép tính gần đúng nhưng không giải pháp nào có thể xử lý việc quản lý bộ nhớ PHP một cách tinh vi.
- tính toán không gian mới được phân bổ
Nếu bạn muốn không gian mới được phân bổ sau một nhiệm vụ, thì bạn phải sử dụng memory_get_usage()
trước và sau khi phân bổ, vì việc sử dụng nó với một bản sao sẽ cho bạn một cái nhìn sai lầm về thực tế.
// open output buffer
echo "Result: ";
// call every function once
range(1,1); memory_get_usage();
echo memory_get_usage()."\n";
$c=range(1,100);
echo memory_get_usage()."\n";
Hãy nhớ rằng nếu bạn muốn lưu trữ kết quả của lần đầu tiên memory_get_usage()
, thì biến đó phải đã tồn tại trước đó và memory_get_usage()
phải được gọi vào một thời điểm khác trước đó và mọi hàm khác cũng vậy.
Nếu bạn muốn lặp lại như trong ví dụ trên, bộ đệm đầu ra của bạn phải được mở sẵn để tránh bộ nhớ kế toán cần thiết để mở bộ đệm đầu ra.
- tính toán không gian cần thiết
Nếu bạn muốn dựa vào một hàm để tính toán không gian cần thiết để lưu trữ bản sao của một biến, đoạn mã sau sẽ thực hiện các tối ưu hóa khác nhau:
<?php
function getMemorySize($value) {
// existing variable with integer value so that the next line
// does not add memory consumption when initiating $start variable
$start=1;
$start=memory_get_usage();
// json functions return less bytes consumptions than serialize
$tmp=json_decode(json_encode($value));
return memory_get_usage() - $start;
}
// open the output buffer, and calls the function one first time
echo ".\n";
getMemorySize(NULL);
// test inside a function in order to not care about memory used
// by the addition of the variable name to the $_GLOBAL array
function test() {
// call the function name once
range(1,1);
// we will compare the two values (see comment above about initialization of $start)
$start=1;
$start=memory_get_usage();
$c=range(1,100);
echo memory_get_usage()-$start."\n";
echo getMemorySize($c)."\n";
}
test();
// same result, this works fine.
// 11044
// 11044
Lưu ý rằng kích thước của tên biến quan trọng trong bộ nhớ được cấp phát.
- Kiểm tra mã của bạn !!
Một biến có kích thước cơ bản được xác định bởi cấu trúc C bên trong được sử dụng trong mã nguồn PHP. Kích thước này không dao động trong trường hợp số lượng. Đối với chuỗi, nó sẽ thêm chiều dài của chuỗi.
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
Nếu chúng ta không tính đến việc khởi tạo tên biến, chúng ta đã biết biến sử dụng bao nhiêu (trong trường hợp là số và chuỗi):
44 byte trong trường hợp số
+ 24 byte trong trường hợp chuỗi
+ độ dài của chuỗi (bao gồm cả ký tự NUL cuối cùng)
(những con số đó có thể thay đổi tùy thuộc vào phiên bản PHP)
Bạn phải làm tròn tối đa 4 byte do căn chỉnh bộ nhớ. Nếu biến nằm trong không gian toàn cục (không nằm trong một hàm), nó cũng sẽ cấp phát thêm 64 byte.
Vì vậy, nếu bạn muốn sử dụng một trong các mã bên trong trang này, bạn phải kiểm tra xem kết quả bằng cách sử dụng một số trường hợp thử nghiệm đơn giản (chuỗi hoặc số) có khớp với những dữ liệu đó có tính đến mọi dấu hiệu trong bài đăng này không (mảng $ _GLOBAL, lệnh gọi hàm đầu tiên, bộ đệm đầu ra, ...)