如何管理 PHP 内存?
How to manage PHP memory?
我编写了一个一次性脚本,用于解析保存在数据库中的 PDF。到目前为止它工作正常,直到我在解析 2,700 多个文档后 运行 内存不足。
脚本的基本流程如下:
- 获取要解析的所有文档 ID 的列表并将其保存为会话中的数组(~155k 文档)。
- 显示包含开始解析按钮的页面
- 单击该按钮时发出 AJAX 请求,该请求将解析会话数组中的前 50 个文档
$files = $_SESSION['files'];
$ids = array();
$slice = array_slice($files, 0, 50);
$files = array_slice($files, 50, null); // remove the 50 we are parsing on this request
if(session_status() == PHP_SESSION_NONE) {
session_start();
}
$_SESSION['files'] = $files;
session_write_close();
for($i = 0; $i < count($slice); $i++) {
$ids[] = ":id_{$i}";
}
$ids = implode(", ", $ids);
$sql = "SELECT d.id, d.filename, d.doc_content
FROM proj_docs d
WHERE d.id IN ({$ids})";
$stmt = oci_parse($objConn, $sql);
for($i = 0; $i < count($slice); $i++) {
oci_bind_by_name($stmt, ":id_{$i}", $slice[$i]);
}
oci_execute($stmt, OCI_DEFAULT);
$cnt = oci_fetch_all($stmt, $data);
oci_free_statement($stmt);
# Do the parsing..
# Output a table row..
- 对 AJAX 请求的响应通常包括脚本是否已完成解析全部 ~155k 文档的状态 - 如果未完成,则会发出另一个 AJAX 请求来解析接下来的 50 . 每次请求之间有5秒的延迟。
问题
- 为什么我 运行 内存不足,而我预计内存使用峰值会在我获得
#1
上所有文档 ID 的列表时出现,因为它包含所有可能的文档不是 几分钟后会话数组少了 2,700 个元素?
- 我看到了一些与我的问题类似的问题,他们建议将内存设置为
unlimited
,我根本不想这样做。其他人建议在适当的时候将我的变量设置为 null
,我这样做了,但在解析了 ~2,700 个文档后我仍然 运行 内存不足。那么我应该尝试哪些其他方法?
# Freeing some memory space
$batch_size = null;
$with_xfa = null;
$non_xfa = null;
$total = null;
$files = null;
$ids = null;
$slice = null;
$sql = null;
$stmt = null;
$objConn = null;
$i = null;
$data = null;
$cnt = null;
$display_class = null;
$display = null;
$even = null;
$tr_class = null;
所以我不太确定为什么,但是将我正在解析的文档数量从每个批次的 50
减少到 10
似乎解决了这个问题。我现在已经超过 5,000 个文档,脚本仍然是 运行。我唯一的猜测是,当我解析 50 个文档时,我一定遇到了很多大文件,这些文件用完了所有分配的内存。
更新#1
我在 8,500 多个文档中遇到另一个关于内存 运行 的错误。我已经将批次进一步减少到每个 5
个文档,明天会看到它是否一直解析所有内容。如果还是不行,我就临时增加分配的内存。
更新 #2
事实证明,我 运行 内存不足的唯一原因是我们显然有多个超过 300MB 的 PDF 文件上传到数据库中。我将分配给 PHP 的内存增加到 512MB,这似乎让我能够完成对所有内容的解析。
我编写了一个一次性脚本,用于解析保存在数据库中的 PDF。到目前为止它工作正常,直到我在解析 2,700 多个文档后 运行 内存不足。
脚本的基本流程如下:
- 获取要解析的所有文档 ID 的列表并将其保存为会话中的数组(~155k 文档)。
- 显示包含开始解析按钮的页面
- 单击该按钮时发出 AJAX 请求,该请求将解析会话数组中的前 50 个文档
$files = $_SESSION['files'];
$ids = array();
$slice = array_slice($files, 0, 50);
$files = array_slice($files, 50, null); // remove the 50 we are parsing on this request
if(session_status() == PHP_SESSION_NONE) {
session_start();
}
$_SESSION['files'] = $files;
session_write_close();
for($i = 0; $i < count($slice); $i++) {
$ids[] = ":id_{$i}";
}
$ids = implode(", ", $ids);
$sql = "SELECT d.id, d.filename, d.doc_content
FROM proj_docs d
WHERE d.id IN ({$ids})";
$stmt = oci_parse($objConn, $sql);
for($i = 0; $i < count($slice); $i++) {
oci_bind_by_name($stmt, ":id_{$i}", $slice[$i]);
}
oci_execute($stmt, OCI_DEFAULT);
$cnt = oci_fetch_all($stmt, $data);
oci_free_statement($stmt);
# Do the parsing..
# Output a table row..
- 对 AJAX 请求的响应通常包括脚本是否已完成解析全部 ~155k 文档的状态 - 如果未完成,则会发出另一个 AJAX 请求来解析接下来的 50 . 每次请求之间有5秒的延迟。
问题
- 为什么我 运行 内存不足,而我预计内存使用峰值会在我获得
#1
上所有文档 ID 的列表时出现,因为它包含所有可能的文档不是 几分钟后会话数组少了 2,700 个元素? - 我看到了一些与我的问题类似的问题,他们建议将内存设置为
unlimited
,我根本不想这样做。其他人建议在适当的时候将我的变量设置为null
,我这样做了,但在解析了 ~2,700 个文档后我仍然 运行 内存不足。那么我应该尝试哪些其他方法?
# Freeing some memory space
$batch_size = null;
$with_xfa = null;
$non_xfa = null;
$total = null;
$files = null;
$ids = null;
$slice = null;
$sql = null;
$stmt = null;
$objConn = null;
$i = null;
$data = null;
$cnt = null;
$display_class = null;
$display = null;
$even = null;
$tr_class = null;
所以我不太确定为什么,但是将我正在解析的文档数量从每个批次的 50
减少到 10
似乎解决了这个问题。我现在已经超过 5,000 个文档,脚本仍然是 运行。我唯一的猜测是,当我解析 50 个文档时,我一定遇到了很多大文件,这些文件用完了所有分配的内存。
更新#1
我在 8,500 多个文档中遇到另一个关于内存 运行 的错误。我已经将批次进一步减少到每个 5
个文档,明天会看到它是否一直解析所有内容。如果还是不行,我就临时增加分配的内存。
更新 #2
事实证明,我 运行 内存不足的唯一原因是我们显然有多个超过 300MB 的 PDF 文件上传到数据库中。我将分配给 PHP 的内存增加到 512MB,这似乎让我能够完成对所有内容的解析。