mysql_free_result()는 mysql_query()로 받은 결과 집합이 붙잡고 있던 메모리를 즉시 돌려주는 함수입니다. 매뉴얼 기준 형태는 다음과 같습니다.
bool mysql_free_result ( resource $result )
인자로 결과 리소스를 넘기면 그 결과에 딸린 메모리를 비우고, 성공하면 true를 돌려줍니다. 옛날 이름인 mysql_freeresult()도 같은 함수로 동작하도록 남아 있었습니다.
안 불러도 되는데 왜 있나
PHP는 스크립트 실행이 끝나면 결과 집합과 DB 연결을 알아서 정리합니다. 그래서 일반적인 웹 페이지, 그러니까 쿼리 몇 개 돌리고 HTML 찍고 끝나는 요청에서는 이 함수를 부르든 말든 체감할 차이가 거의 없습니다. mysql_close()도 마찬가지로 안 불러도 요청이 끝나면 연결이 닫힙니다.
차이가 나는 건 스크립트 하나가 오래 살아 있는 경우입니다. 수만 건을 조회해 엑셀로 내보내는 페이지, 크론으로 도는 배치 스크립트, 반복문 안에서 큰 결과를 계속 받아 오는 코드 같은 것들이죠. 이때 다 쓴 결과를 바로 풀어 주지 않으면 다음 쿼리 결과가 그 위에 쌓이면서 memory_limit에 걸려 "Allowed memory size exhausted" 오류로 멈출 수 있습니다. 결과를 다 읽었으면 그 자리에서 해제해 두는 습관이 이런 상황을 막아 줍니다.
명시적으로 해제해 두면 코드를 읽는 사람 입장에서도 "이 결과는 여기서 끝"이라는 게 분명해집니다. 필수는 아니지만 큰 결과를 다룰 때는 넣어 두는 쪽을 권합니다.
지금은 mysql_* 함수를 쓸 수 없다
중요한 점이 하나 있습니다. mysql_ 로 시작하는 확장은 PHP 5.5에서 사용 중단이 예고됐고 PHP 7.0에서 완전히 빠졌습니다. 지금 PHP 7·8 환경에서 mysql_free_result()를 호출하면 "Call to undefined function" 치명적 오류가 납니다. 오래된 소스를 옮겨 왔는데 화면이 하얗게 나온다면 이 계열 함수가 남아 있는지부터 찾아보세요.
같은 일을 mysqli에서는 이렇게 합니다.
<?php
$result = mysqli_query($con, "SELECT * FROM big_table");
while ($row = mysqli_fetch_assoc($result)) {
// 행 처리
}
mysqli_free_result($result); // 절차형
// 객체형이라면
// $result->free();
mysqli에서 MYSQLI_USE_RESULT(비버퍼 모드)로 조회했다면 해제가 사실상 필수입니다. 결과를 끝까지 읽거나 풀어 주기 전에 같은 연결로 다른 쿼리를 보내면 "Commands out of sync" 오류가 나기 때문입니다. 대용량 조회를 비버퍼로 돌릴 때 자주 막히는 지점이에요.
PDO를 쓴다면 대응하는 동작이 closeCursor()입니다.
<?php
$stmt = $pdo->query("SELECT * FROM big_table");
foreach ($stmt as $row) {
// 행 처리
}
$stmt->closeCursor();
$stmt = null;
PDO는 문장 객체에 대한 참조가 사라지면 정리되므로, 함수 안에서 쓰고 끝나는 코드라면 따로 신경 쓸 일이 적습니다. 반복문 안에서 같은 변수에 계속 새 결과를 받는 구조라면 closeCursor()를 넣어 두는 편이 안전합니다.