문제

내 PHP 앱에는 레코드를 가져올 수있는 가져 오기 스크립트가 있습니다.

현재 CSV 파일에서 가져오고 있습니다. 그것은 CSV 파일의 각 줄, fgetcsv를 사용하여 한 번에 한 줄 씩 읽고 있으며, 각 줄에 대해 많이 데이터베이스 쿼리를 포함하여 해당 레코드에서 처리 한 다음 다음 줄로 이동합니다. 더 많은 메모리를 계속 누적 할 필요는 없습니다.

약 2500 개의 기록을 수입 한 후, PHP는 메모리 제한 (132MB 정도)을 넘어 섰다고 밝혔다.

CSV 파일 자체는 단지 몇 메그 일뿐입니다. 다른 처리는 많은 문자열 비교, 차이 등을 수행합니다. 나는 엄청난 양의 코드가 작동하며 '가장 작은 재생산을 내기가 어려울 것입니다. 견본'.

그러한 문제를 찾고 고치는 데 좋은 방법은 무엇입니까?

발견 된 문제의 원인

런타임 동안 모든 데이터베이스 쿼리를 기록하는 디버그 클래스가 있습니다. 그래서 약 30kb 길이의 SQL 문자열은 기억에 남아있었습니다. 나는 이것이 오랫동안 실행되도록 설계된 스크립트에 적합하지 않다는 것을 알고 있습니다.

다른 메모리 누출 소스가있을 수 있지만 이것이 내 문제의 원인이라고 확신합니다.

도움이 되었습니까?

해결책

코드를 살펴 보는 데 도움이되지만 직접 디버깅을 원한다면 살펴보십시오. xdebug, 응용 프로그램을 프로파일 링하는 데 도움이됩니다.

물론, 당신이하고있는 일에 따라, 132MB는 이미 2500 개의 레코드에 대해 이미 높은 것으로 보이지만 일부 메모리를 축적 할 수 있습니다. 물론 당신은 할 수 메모리 제한 조정 필요한 경우 php.ini에서.

당신이 읽고있는 CSV 파일은 얼마나 큰가요? 그리고 어떤 대상과 종류의 처리를하고 있습니까?

다른 팁

실제로 스크립트에 중단되는 메모리 누출이 한두 개의 메모리 누출이 있다고 의심한다면 다음 단계를 수행해야합니다.

  • 변화 memory_limit 500KB와 같은 작은 것
  • 각 행에 적용되는 처리 단계 중 하나를 제외한 모든 것을 설명하십시오.
  • 전체 CSV 파일을 통해 제한된 처리를 실행하고 완료 할 수 있는지 확인하십시오.
  • 점차적으로 더 많은 단계를 추가하고 메모리 사용이 급증하는지 확인하십시오.

예시:

ini_set('memory_limit', 1024 * 500);
$fp = fopen("test.csv", 'r');
while($row = fgetcsv($fp)) {
    validate_row($row);         // step 1: validate
    // add these back in one by one and keep an eye on memory usage
    //calculate_fizz($row);     // step 2: fizz
    //calculate_buzz($row);     // step 3: buzz
    //triangulate($row);        // step 4: triangulate
}
echo "Memory used: ", memory_get_peak_usage(), "\n";

최악의 시나리오는이 시나리오입니다 모두 처리 단계는 약간 비효율적이며 모든 처리 단계는 모든 것을 최적화해야합니다.

변수를 수행 한 후에 변수를 지우는 방법에 따라 다릅니다.

레코드가 완료된 것 같지만 여전히 정보를 어딘가에 저장하고 있습니다. 사용 unset () 의심스러운 경우 변수를 정리합니다.

도움이되지 않으면 최소한의 메모리가 어디로 가고 있는지 확인하려면 최소한의 재생 코드 샘플을 제공하십시오.

BTW, 문제를 재현 할 가장 작은 코드 샘플을 생성하는 것은 훌륭한 디버깅 기술입니다.

PHP5.3의 로컬 설치를 시도하고 http://www.php.net/manual/en/function.gc-collect-cycles.php로 전화 할 수 있습니다.

gc_collect_cycles - 기존 쓰레기주기의 힘 수집

상황이 향상되면 최소한 문제를 확인했습니다.

파일을 어떻게 읽고 있습니까? Fread/FileGetContents 또는 기타 기능을 사용하는 경우 전체 파일이 호출 시간에로드되므로 전체 파일 크기 (또는 Fread가 많이로드)를 소비하게됩니다. 그러나 사용하는 경우 fgetcsv 줄의 길이에 따라 한 번에 한 줄만 읽으면 메모리에서 훨씬 쉬울 수 있습니다.

또한 각 루프에서 가능한 많은 변수를 재사용하고 있는지 확인하십시오. 많은 양의 데이터가있는 배열이 없는지 확인하십시오.

마지막 참고로 루프 전에 파일을 열고 후에 닫는지 확인하십시오.

$fh = fopen(...);
while(true)
{
//...
}
fclose($fh);

당신은 정말로 이것을하고 싶지 않습니다.

while(true)
{
$fh = fopen(...);
//...
fclose($fh);
}

그리고 다른 사람들이 말했듯이 코드를 보지 않고는 말하기가 어렵습니다.

코드를 보지 않고 원인을 말하기는 어렵습니다. 그러나 일반적인 문제는 재귀 참조입니다. 객체 A는 객체 B와 다른 방법으로 포인트를 사용하여 GC가 망칠 수 있습니다.

현재 파일을 처리하는 방법을 모르겠지만 한 번에 한 행 씩 파일 만 읽으려고 시도 할 수 있습니다. 전체 파일을 한 번에 읽으면 더 많은 메모리를 소비 할 수 있습니다.

이것은 실제로 배치 처리 작업을 위해 종종 파이썬을 선호하는 이유 중 하나입니다.

php.ini에서 memory_limit을 변경할 수 있습니까?

또한 변수에 대해 UNSET ($ var)를 수행 할 수 있습니다. $ var = null도 도움이 될 수 있습니까?

이 질문도 참조하십시오. php : unset () 또는 $ var = null을 사용하여 메모리를 해제하는 데 더 나은 것은 무엇입니까?

나는 같은 문제가 있었고 데이터베이스 프로파일 링 (Zend_db_profiler_firebug) 때문이었습니다. 제 경우에는 분당 1MB가 누출되었습니다. 이 스크립트는 며칠 동안 실행되어야하므로 몇 시간 안에 충돌합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top