You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Mar 6, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Mar 6, 2026. It is now read-only.
Version 2.4.0 of the library is allocating much more memory that the previous version, 2.3.1, when running multiple queries.
In particular, it seems that the QueryJob object is retaining the results of the query internally, and that memory is not deallocated.
Please note that we are storing a reference to the QueryJob objects, but not to the resulting DataFrames.
importosimportpsutilfromgoogle.cloudimportbigqueryif__name__=='__main__':
client=bigquery.Client()
process=psutil.Process(os.getpid())
print(f"Initial memory used: {process.memory_info().rss/1e6:.0f} MB")
jobs= []
foriinrange(10):
job=client.query("SELECT x FROM UNNEST(GENERATE_ARRAY(1, 1000000)) AS x")
job.result().to_dataframe()
jobs.append(job)
print(f"Memory used: {process.memory_info().rss/1e6:.0f} MB")
Reacted by Riccardo Albertazzi, Andrea Bignoli, Giulio Cataldi, Davide Pedranz, Gabriele Platania, Enrico Martinelli, Paul Matthews, Andrea Riva, Lorenzo Migliorino, Aldo D'Aquino and 6 more
We are caching the first page of results in the QueryJob class, which is why the memory is still being used in this example. (You're hanging on to the QueryJob class.)
What's the reason you'd want to retain a reference to this job class?
Workaround: You can call job._query_results = None once you are finished with getting results from the job.
We can investigate doing this automatically, though it's a bit tricky since the first page of results aren't actually used until the RowIterator is iterated over.
@tswast the reason to keep around the QueryJob objects is to launch multiple queries in parallel, and then call .result() on them as they finish. Thanks for the workaround!
I'm also doing some more intense benchmarking with a variety of table / row sizes, as it's clear that there are many combinations for which this caching behavior was a regression.
Activity
tswast commentedon Nov 19, 2020
We are caching the first page of results in the QueryJob class, which is why the memory is still being used in this example. (You're hanging on to the QueryJob class.)
What's the reason you'd want to retain a reference to this job class?
tswast commentedon Nov 19, 2020
Workaround: You can call
job._query_results = Noneonce you are finished with getting results from the job.We can investigate doing this automatically, though it's a bit tricky since the first page of results aren't actually used until the RowIterator is iterated over.
[-]Memory leak in 2.4.0[/-][+]increased memory usage in 2.4.0[/+]pietrodn commentedon Nov 19, 2020
@tswast the reason to keep around the QueryJob objects is to launch multiple queries in parallel, and then call
.result()on them as they finish. Thanks for the workaround!tswast commentedon Nov 24, 2020
I'm reverting this change in #400
I'm also doing some more intense benchmarking with a variety of table / row sizes, as it's clear that there are many combinations for which this caching behavior was a regression.
perf: don't fetch rows when waiting for query to finish (#400)