Как узнать размер массива php
Отсутсвие жесткой типизации в PHP, на первый взгляд упрощает разработку — не нужно задавать типы переменных, заботиться о конвертации — все делает интепритатор. Конечно же за простоту и удобство прийдется платить и чем важнее производительность тем больше. Ниже речь пойдет о любимых массивах, быстрых и простых на первый взгляд, но прожорливых к памяти при больших объемах.
Массивы в PHP — некий универсальных тип данных, для хранения как векторных, так и многомерных списков, устанавливающий соответствие между ключем и значением (причем один массив может содержать и целочисленные, и строчные ключи одновременно). Кругом массивов создана куча функций позволяющих работать с ними как с очередями, стеком, сортировать и др.
Наверняка это удобно работать с универсальным типом данных, для которого, как и везде в PHP, не нужно указывать типизацию — в одну корзину можно ложить и объекты, и строки, да в общем что угодно.
А как же интерпритатор работает с нетипизированными переменными?
Интерпритатор хранит каждую переменную в виде структуры Zval, содержащую поля:
- zvalue_value value — значение переменной
- zend_uint refcount__gc — количество ссылок на переменную (если оно равно 0 — уборщик мусора удаляет переменную и освобождает память)
- zend_uchar type — тип переменной
- zend_uchar is_ref__gc — флаг определяющий, что переменная является ссылкой
Нас интересует поле value, которое содержит значение переменной представленое в виде объединения, содержащего поля для всех типов данных:
typedef union _zvalue_value < long lval — численные + булевые и ресурсы (их идентификаторы) double dval — double struct < char *val; int len; >str - строка HashTable *ht — массив zend_object_value obj — объект и null >
В зависимости от типа присваемых данных, значение записывается в нужное поле (например а=1 запишется в lval).
Давайте взвесим массив
Измерим, сколько памяти занимает один целочисленный элемент массива. Сначала взвесим пустой массив:
$p1 = memory_get_usage(); $a = array(); echo (memory_get_usage() - $p1);
Теперь один элемент:
$p1 = memory_get_usage(); $a = array(1); echo (memory_get_usage() - $p1);
Ну и чтобы наверняка — два элемента:
$p1 = memory_get_usage(); $a = array(1,2); echo (memory_get_usage() - $p1);
У меня один элемент занял 136 байт, что вроде бы не так и много. Но представим, что имеем небольшую матрицу, например игровое поле 100х100, каждая клетка которого содержит целочисленную переменную статуса:
136 * 10000 = 1360000 = ~1.4Мб
Ничего так получилось, правда? На одну только небольшую сетку полтора мегабайта. А давайте попробуем вместо переменной статуса, использовать простой объект:
class cellStatus < protected $status = 0; public function getStatus() < return $this->status; > public function setStatus($values) < $this->status = $value; > >
У меня получилось 5.6Мб! Представьте что будет, если сделать поле 1000х1000, даже с целочисленными статусами.
Плохи наши дела
Вот и аукнулась нестрогая типизация — переменная, которая при строгой весила бы 8 байт, весит 136, из-за чего сильно увеличивается потребление памяти.
Так что же делать, чтобы избежать огромных затрат? Совет «не использовать массивы» наверно прозвучит глупо и всеравно не поможет, поэтому советую использовать структуры данных SPL. Например, SPL массив из 10 элементов:
$a = new SplFixedArray(10);
использует меньше памяти чем обычный, хотя и накладывает некоторые ограничения.
В тему:
- Быстрый код
- Компиляция PHP приложений — HipHop-php
Если пост понравился — нажмите на +1 — мне будет приятно.
Как узнать размер массива php
Здравствуйте всем.
Что-то заинтересовал меня такой вопрос:
массив Arr(4,6,3,9, .. и так n значений)
Возможно ли определить это самое n?
То, что n не более 60 я знаю.
Чисто ради любопытства.
Пользователь
Сообщений: 3672 Регистрация: 23.12.2012
11.05.2011 22:00:28
Sub test()
a = Array(4, 6, 3, 9, 8)
n = UBound(a) — LBound(a) + 1
MsgBox n
End Sub
Пользователь
Сообщений: 3103 Регистрация: 22.12.2012
Excel,MSSQL,Oracle,Qlik
11.05.2011 22:07:35
Что-то заинтересовал меня такой вопрос:
массив Arr(4,6,3,9, .. и так n значений)
Возможно ли определить это самое n?
То, что n не более 60 я знаю.
Чисто ради любопытства.
Sub test()
Dim Arr(4, 6, 3, 9)
For i = 1 To 60
on error resume next
tmp= UBound(Arr, i)
if err.number<>0 then exit for :msgbox i
Next
End Sub
Пользователь
Сообщений: 10514 Регистрация: 21.12.2012
11.05.2011 22:08:00
Нет, это мы определим «длину» каждой размерности. А я хотел узнать, сколько всего этих размерностей.
зы. неясно наверно выражаюсь, после праздников.
Arr(1 to 5, 4 to 7, 2 to 9, 5 to 7)
Как узнать, что массив четырехмерный.
Пользователь
Сообщений: 10514 Регистрация: 21.12.2012
11.05.2011 22:10:54
Пока сочинял для EducatedFool, появилось решение от R Dmitry.
Спасибо, в принципе так устроит.
Пользователь
Сообщений: 3103 Регистрация: 22.12.2012
Excel,MSSQL,Oracle,Qlik
11.05.2011 22:14:18
Sub test()
Dim Arr(4, 6, 3, 9)
For i = 1 To 60
On Error Resume Next
tmp = UBound(Arr, i)
If Err.Number > 0 Then MsgBox i — 1: Exit For:
Next
End Sub
Михаил так правильней , а то дописал код в форум не проверив 🙂
Пользователь
Сообщений: 10514 Регистрация: 21.12.2012
11.05.2011 22:16:36
Не, Дим, попробовал ради интереса — ничего не выдает. 🙁
Ну попробую на этой основе что нибудь придумать.
Пользователь
Сообщений: 10514 Регистрация: 21.12.2012
11.05.2011 22:19:22
Да, второй вариант то что надо. Спасибо!
Пользователь
Сообщений: 3103 Регистрация: 22.12.2012
Excel,MSSQL,Oracle,Qlik
11.05.2011 22:20:34
Ну попробую на этой основе что нибудь придумать.
Михаил, я исправил ошибку, у меня работает. Просто писал прямо в форум.
Пользователь
Сообщений: 10514 Регистрация: 21.12.2012
11.05.2011 22:20:59
Правда чуть изменить пришлось
Dim Arr(4, 6, 3, 9, 8), i, tmp
🙂
Пользователь
Сообщений: 11312 Регистрация: 01.01.1970
11.05.2011 23:47:01
Ну попробую на этой основе что нибудь придумать.
Ну вот, ещё одного формулиста потеряли 🙂
Планета становиться VB-образной 🙂
Пользователь
Сообщений: 3139 Регистрация: 23.12.2012
12.05.2011 00:22:48
И это логично 🙂
Зачем пытаться выжать из «Запорожца» 150 км/ч, если можно пересесть на «Мерседес».
Пользователь
Сообщений: 47199 Регистрация: 15.09.2012
12.05.2011 10:17:29
Не обижать «Запорожец»! 🙂
Вопрос армянскому радио:
— Может ли «Запорожец» развить скорость 200 км/ч?
— Может. Если сбросить его с горы Арарат.
Пользователь
Сообщений: 10514 Регистрация: 21.12.2012
12.05.2011 12:13:53
ЗапорожецЪ — моя любимая машина. Я себе в 1985 новый сделал, 965 модели («горбатый»).
По проходимости, особенно если в нем пять здоровых мужиков едут — любой джип и рядом не стоял. 🙂
Пользователь
Сообщений: 7207 Регистрация: 21.12.2012
12.05.2011 12:19:41
Подтверждаю! 🙂
Пользователь
Сообщений: 5192 Регистрация: 16.01.2013
12.05.2011 15:42:48
вот вам мерседец 🙂
Declare Function VarPtrArray Lib «msvbvm60.dll» Alias «VarPtr» (Var() As Any) As Long
Declare Sub GetMem4 Lib «msvbvm60.dll» (ByVal SrcPointer As Long, ByVal DstPointer As Long)
Sub t()
Dim ar(1, 2, 3, 4, 5, 6, 7)
Dim p&, dm As Integer
GetMem4 VarPtrArray(ar()), VarPtr(p)
GetMem4 p, VarPtr(dm)
msgbox «вы объявили «& p «измерений»
End Sub
Живи и дай жить..
Пользователь
Сообщений: 5192 Регистрация: 16.01.2013
12.05.2011 15:47:24
а точнее( а главное безопаснее):
Option Explicit
Option Base 0
Declare Function VarPtrArray Lib «msvbvm60.dll» Alias «VarPtr» (Var() As Any) As Long
Declare Sub GetMem4 Lib «msvbvm60.dll» (ByVal SrcPointer As Long, ByVal DstPointer As Long)
Sub t()
Dim ar(1, 2, 3, 4, 5, 6, 7)
Dim p&, dm(1) As Integer
GetMem4 VarPtrArray(ar()), VarPtr(p)
GetMem4 p, VarPtr(dm(0))
MsgBox «вы объявили » & dm(0) & » измерений»
End Sub
Живи и дай жить..
09.09.2011 18:40:19
Option Explicit
Option Base 0
Declare Function VarPtrArray Lib «msvbvm60.dll» Alias «VarPtr» (Var() As Any) As Long
Declare Sub GetMem4 Lib «msvbvm60.dll» (ByVal SrcPointer As Long, ByVal DstPointer As Long)
Sub t()
Dim ar(1, 2, 3, 4, 5, 6, 7)
Dim p&, dm(1) As Integer
GetMem4 VarPtrArray(ar()), VarPtr(p)
GetMem4 p, VarPtr(dm(0))
MsgBox «вы объявили » & dm(0) & » измерений»
End Sub
А вот как определить размерность 2-мерного массива ?
DIM Mas(1 TO 7, 1 TO 10)’ ?
